модуль ActionView::Helpers::UrlHelper
Хелперы URL Action View
Предоставляет набор методов для создания ссылок и получения URL, зависящих от подсистемы маршрутизации (см. ActionDispatch::Routing). Это позволяет использовать один и тот же формат ссылок в представлениях и контроллерах.
Константы
- BUTTON_TAG_METHOD_VERBS
-
Этот хелпер можно подключить к любому классу, включающему хелперы URL маршрутов (routes.url_helpers). Некоторые предоставляемые здесь методы работают только в контексте запроса (например,
link_to_unless_current); в таком случае контекст должен предоставлять метод request. - STRINGIFIED_COMMON_METHODS
Открытые методы экземпляра
# File actionview/lib/action_view/helpers/url_helper.rb, line 296
def button_to(name = nil, options = nil, html_options = nil, &block)
html_options, options = options, name if block_given?
html_options ||= {}
html_options = html_options.stringify_keys
url =
case options
when FalseClass then nil
else url_for(options)
end
remote = html_options.delete("remote")
params = html_options.delete("params")
authenticity_token = html_options.delete("authenticity_token")
method = (html_options.delete("method").presence || method_for_options(options)).to_s
method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : "".html_safe
form_method = method == "get" ? "get" : "post"
form_options = html_options.delete("form") || {}
form_options[:class] ||= html_options.delete("form_class") || "button_to"
form_options[:method] = form_method
form_options[:action] = url
form_options[:'data-remote'] = true if remote
request_token_tag = if form_method == "post"
request_method = method.empty? ? "post" : method
token_tag(authenticity_token, form_options: { action: url, method: request_method })
else
""
end
html_options = convert_options_to_data_attributes(options, html_options)
html_options["type"] = "submit"
button = if block_given?
content_tag("button", html_options, &block)
elsif button_to_generates_button_tag
content_tag("button", name || url, html_options, &block)
else
html_options["value"] = name || url
tag("input", html_options)
end
inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
if params
to_form_params(params).each do |param|
options = { type: "hidden", name: param[:name], value: param[:value] }
options[:autocomplete] = "off" unless ActionView::Base.remove_hidden_field_autocomplete
inner_tags.safe_concat tag(:input, **options)
end
end
html = content_tag("form", inner_tags, form_options)
prevent_content_exfiltration(html)
end Создает форму с одной кнопкой, которая отправляет запрос на URL, сформированный набором options. Это самый безопасный способ гарантировать, что ссылки, изменяющие ваши данные, не будут активированы поисковыми ботами или ускорителями.
Поведение формы и кнопки можно настроить с помощью html_options. Большинство значений в html_options передаются элементу кнопки. Например, передача параметра :class в html_options задаст атрибут class элемента кнопки.
Атрибут class элемента формы можно задать, передав параметр :form_class в html_options. По умолчанию он равен "button_to", чтобы можно было задавать стили для формы и ее дочерних элементов.
Если объект не сохранен, форма по умолчанию отправляет запрос POST; если же объект сохранен, она отправит запрос PATCH. Чтобы указать другой HTTP-метод, используйте параметр :method в html_options.
Если HTML-кнопка, созданная методом button_to, не подходит для вашей разметки, можно воспользоваться методом link_to с атрибутом data-turbo-method, как описано в документации метода link_to.
Параметры
Хеш options принимает те же параметры, что и url_for. Чтобы создать элемент <form> без атрибута [action], передайте false:
<%= button_to "New", false %> # => "<form method="post" class="button_to"> # <button type="submit">New</button> # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/> # </form>"
Большинство значений в html_options передаются элементу кнопки, но есть несколько особых параметров:
-
:method— символ HTTP-метода. Поддерживаются методы:post,:get,:delete,:patchи:put. По умолчанию используется:post. -
:disabled— если задано значение true, будет создана отключенная кнопка. -
:data— этот параметр можно использовать для добавления пользовательских атрибутов data. -
:form— этот хеш задает атрибуты формы. -
:form_class— этот параметр задает класс формы, в которой будет размещена кнопка отправки. -
:params— хеш параметров, которые будут отображены в форме как скрытые поля.
Примеры
<%= button_to "New", action: "new" %>
# => "<form method="post" action="/controller/new" class="button_to">
# <button type="submit">New</button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
# </form>"
<%= button_to "New", new_article_path %>
# => "<form method="post" action="/articles/new" class="button_to">
# <button type="submit">New</button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
# </form>"
<%= button_to "New", new_article_path, params: { time: Time.now } %>
# => "<form method="post" action="/articles/new" class="button_to">
# <button type="submit">New</button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# <input type="hidden" name="time" value="2021-04-08 14:06:09 -0500" autocomplete="off">
# </form>"
<%= button_to [:make_happy, @user] do %>
Make happy <strong><%= @user.name %></strong>
<% end %>
# => "<form method="post" action="/users/1/make_happy" class="button_to">
# <button type="submit">
# Make happy <strong><%= @user.name %></strong>
# </button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
# </form>"
<%= button_to "New", { action: "new" }, form_class: "new-thing" %>
# => "<form method="post" action="/controller/new" class="new-thing">
# <button type="submit">New</button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
# </form>"
<%= button_to "Create", { action: "create" }, form: { "data-type" => "json" } %>
# => "<form method="post" action="/images/create" class="button_to" data-type="json">
# <button type="submit">Create</button>
# <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
# </form>" # File actionview/lib/action_view/helpers/url_helper.rb, line 559
def current_page?(options = nil, check_parameters: false, method: :get, **options_as_kwargs)
unless request
raise "You cannot use helpers that need to determine the current " \
"page unless your view context provides a Request object " \
"in a #request method"
end
if options.is_a?(Hash)
check_parameters = options.delete(:check_parameters) { check_parameters }
method = options.delete(:method) { method }
else
options ||= options_as_kwargs
end
method_matches = case method
when :get
request.get? || request.head?
when Array
method.include?(request.method_symbol) || (method.include?(:get) && request.head?)
else
method == request.method_symbol
end
return false unless method_matches
url_string = URI::RFC2396_PARSER.unescape(url_for(options)).force_encoding(Encoding::BINARY)
# We ignore any extra parameters in the request_uri if the
# submitted URL doesn't have any either. This lets the function
# work with things like ?order=asc
# the behavior can be disabled with check_parameters: true
request_uri = url_string.index("?") || check_parameters ? request.fullpath : request.path
request_uri = URI::RFC2396_PARSER.unescape(request_uri).force_encoding(Encoding::BINARY)
if %r{^\w+://}.match?(url_string)
request_uri = +"#{request.protocol}#{request.host_with_port}#{request_uri}"
end
remove_trailing_slash!(url_string)
remove_trailing_slash!(request_uri)
url_string == request_uri
end Возвращает true, если URI текущего запроса был сформирован указанным options.
Примеры
Предположим, что мы находимся в действии http://www.example.com/shop/checkout?order=desc&page=1.
current_page?(action: 'process')
# => false
current_page?(action: 'checkout')
# => true
current_page?(controller: 'library', action: 'checkout')
# => false
current_page?(controller: 'shop', action: 'checkout')
# => true
current_page?(controller: 'shop', action: 'checkout', order: 'asc')
# => false
current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '1')
# => true
current_page?(controller: 'shop', action: 'checkout', order: 'desc', page: '2')
# => false
current_page?('http://www.example.com/shop/checkout')
# => true
current_page?('http://www.example.com/shop/checkout', check_parameters: true)
# => false
current_page?('/shop/checkout')
# => true
current_page?('http://www.example.com/shop/checkout?order=desc&page=1')
# => true
Разные действия могут использовать один путь URL, но разные HTTP-методы. Предположим, мы отправили POST-запрос на http://www.example.com/products и отобразили ошибку валидации.
current_page?(controller: 'product', action: 'index') # => false current_page?(controller: 'product', action: 'create') # => false current_page?(controller: 'product', action: 'create', method: :post) # => true current_page?(controller: 'product', action: 'index', method: [:get, :post]) # => true
Вместо строк можно также передавать аргументы-символы.
# File actionview/lib/action_view/helpers/url_helper.rb, line 198
def link_to(name = nil, options = nil, html_options = nil, &block)
html_options, options, name = options, name, block if block_given?
options ||= {}
html_options = convert_options_to_data_attributes(options, html_options)
url = url_target(name, options)
html_options["href"] ||= url
content_tag("a", name || url, html_options, &block)
end Создает элемент ссылки с заданным name, используя URL, сформированный набором options. Допустимые параметры см. в документации url_for. Вместо хеша параметров можно передать строку: тогда будет создан элемент ссылки, в котором значение строки используется как href. Если вместо хеша параметров передать символ :back, будет создана ссылка на страницу-источник (если источник отсутствует, вместо нее будет использована ссылка JavaScript для возврата назад). Если в качестве имени передать nil, именем ссылки станет ее значение.
Сигнатуры
link_to(body, url, html_options = {})
# url is a String; you can use URL helpers like
# posts_path
link_to(body, url_options = {}, html_options = {})
# url_options, except :method, is passed to url_for
link_to(options = {}, html_options = {}) do
# name
end
link_to(url, html_options = {}) do
# name
end
link_to(active_record_model)
Параметры
-
:data— этот параметр можно использовать для добавления пользовательских атрибутов data.
Примеры
Поскольку метод link_to использует url_for, он поддерживает как аргументы controller/action/id в старом стиле, так и новые RESTful-маршруты. В современном Rails предпочтительны RESTful-маршруты, поэтому создавайте приложение на основе ресурсов и используйте
link_to "Profile", profile_path(@profile) # => <a href="/profiles/1">Profile</a>
или еще более краткий вариант
link_to "Profile", @profile # => <a href="/profiles/1">Profile</a>
вместо более старого многословного варианта, не ориентированного на ресурсы
link_to "Profile", controller: "profiles", action: "show", id: @profile # => <a href="/profiles/show/1">Profile</a>
Аналогично,
link_to "Profiles", profiles_path # => <a href="/profiles">Profiles</a>
лучше, чем
link_to "Profiles", controller: "profiles" # => <a href="/profiles">Profiles</a>
Если name равен nil, вместо него будет показан href
link_to nil, "http://example.com" # => <a href="http://www.example.com">http://www.example.com</a>
Еще короче: если name — это модель Active Record, в которой определен метод to_s, возвращающий значение по умолчанию или атрибут экземпляра модели
link_to @profile # => <a href="http://www.example.com/profiles/1">Eileen</a>
Также можно использовать блок, если цель ссылки сложно уместить в параметре name. Например, ERB:
<%= link_to(@profile) do %>
<strong><%= @profile.name %></strong> -- <span>Check it out!</span>
<% end %>
# => <a href="/profiles/1">
<strong>David</strong> -- <span>Check it out!</span>
</a> Классы и идентификаторы CSS легко задать:
link_to "Articles", articles_path, id: "news", class: "article" # => <a href="/articles" class="article" id="news">Articles</a>
Будьте внимательны при использовании старого стиля аргументов: требуется дополнительный литерал хеша:
link_to "Articles", { controller: "articles" }, id: "news", class: "article"
# => <a href="/articles" class="article" id="news">Articles</a>
Если опустить хеш, ссылка будет сформирована неправильно:
link_to "WRONG!", controller: "articles", id: "news", class: "article" # => <a href="/articles/index/news?class=article">WRONG!</a>
Метод link_to также позволяет создавать ссылки с якорями или строками запроса:
link_to "Comment wall", profile_path(@profile, anchor: "wall") # => <a href="/profiles/1#wall">Comment wall</a> link_to "Ruby on Rails search", controller: "searches", query: "ruby on rails" # => <a href="/searches?query=ruby+on+rails">Ruby on Rails search</a> link_to "Nonsense search", searches_path(foo: "bar", baz: "quux") # => <a href="/searches?foo=bar&baz=quux">Nonsense search</a>
Можно задавать любые атрибуты ссылки, например target, rel, type:
link_to "External link", "http://www.rubyonrails.org/", target: "_blank", rel: "nofollow" # => <a href="http://www.rubyonrails.org/" target="_blank" rel="nofollow">External link</a>
Turbo
Rails 7 поставляется с включенным по умолчанию Turbo. Turbo предоставляет следующие параметры :data:
-
turbo_method: symbol of HTTP verb— выполняет переход Turbo по ссылке с указанным HTTP-методом. Для запросов, отличных отGET, рекомендуется использовать формы. Применяйтеdata-turbo-methodтолько в тех случаях, когда форма невозможна. -
turbo_confirm: "question?"— добавляет к ссылке диалог подтверждения с указанным значением.
Дополнительные сведения о перечисленных выше параметрах см. в руководстве Turbo.
Примеры
link_to "Delete profile", @profile, data: { turbo_method: :delete }
# => <a href="/profiles/1" data-turbo-method="delete">Delete profile</a>
link_to "Visit Other Site", "https://rubyonrails.org/", data: { turbo_confirm: "Are you sure?" }
# => <a href="https://rubyonrails.org/" data-turbo-confirm="Are you sure?">Visit Other Site</a>
# File actionview/lib/action_view/helpers/url_helper.rb, line 438
def link_to_if(condition, name, options = {}, html_options = {}, &block)
if condition
link_to(name, options, html_options)
else
if block_given?
block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
else
ERB::Util.html_escape(name)
end
end
end Если condition равно true, создает тег ссылки с заданным name, используя URL, сформированный набором options; в противном случае возвращает только имя. Чтобы изменить поведение по умолчанию, можно передать блок, принимающий имя или полный список аргументов для link_to_if.
Примеры
<%= link_to_if(@current_user.nil?, "Login", { controller: "sessions", action: "new" }) %>
# If the user isn't logged in...
# => <a href="/sessions/new/">Login</a>
<%=
link_to_if(@current_user.nil?, "Login", { controller: "sessions", action: "new" }) do
link_to(@current_user.login, { controller: "accounts", action: "show", id: @current_user })
end
%>
# If the user isn't logged in...
# => <a href="/sessions/new/">Login</a>
# If they are logged in...
# => <a href="/accounts/show/3">my_username</a> # File actionview/lib/action_view/helpers/url_helper.rb, line 415
def link_to_unless(condition, name, options = {}, html_options = {}, &block)
link_to_if !condition, name, options, html_options, &block
end Создает тег ссылки с заданным name, используя URL, сформированный набором options, если condition не равно true; в противном случае возвращает только имя. Чтобы изменить поведение по умолчанию (например, показывать ссылку для входа вместо обычного текста ссылки), можно передать блок, принимающий имя или полный список аргументов для link_to_unless.
Примеры
<%= link_to_unless(@current_user.nil?, "Reply", { action: "reply" }) %>
# If the user is logged in...
# => <a href="/controller/reply/">Reply</a>
<%=
link_to_unless(@current_user.nil?, "Reply", { action: "reply" }) do |name|
link_to(name, { controller: "accounts", action: "signup" })
end
%>
# If the user is logged in...
# => <a href="/controller/reply/">Reply</a>
# If not...
# => <a href="/accounts/signup">Reply</a> # File actionview/lib/action_view/helpers/url_helper.rb, line 391
def link_to_unless_current(name, options = {}, html_options = {}, &block)
link_to_unless current_page?(options), name, options, html_options, &block
end Создает тег ссылки с заданным name, используя URL, сформированный набором options, если URI текущего запроса не совпадает с URI ссылки; в противном случае возвращается только имя (или вызывается переданный блок). Методу link_to_unless_current можно передать блок, который изменит поведение по умолчанию (например, покажет ссылку «Начать здесь» вместо текста ссылки).
Примеры
Предположим, у вас есть меню навигации…
<ul id="navbar">
<li><%= link_to_unless_current("Home", { action: "index" }) %></li>
<li><%= link_to_unless_current("About Us", { action: "about" }) %></li>
</ul> В действии «about» оно отобразит…
<ul id="navbar"> <li><a href="/controller/index">Home</a></li> <li>About Us</li> </ul>
…а в действии «index» оно отобразит:
<ul id="navbar"> <li>Home</li> <li><a href="/controller/about">About Us</a></li> </ul>
Неявно переданный методу link_to_unless_current блок выполняется, если текущее действие совпадает с указанным. Поэтому, если у нас есть страница комментариев и вместо ссылки на нее мы хотим отобразить ссылку «Назад», можно сделать примерно так…
<%=
link_to_unless_current("Comment", { controller: "comments", action: "new" }) do
link_to("Go back", { controller: "posts", action: "index" })
end
%> # File actionview/lib/action_view/helpers/url_helper.rb, line 488
def mail_to(email_address, name = nil, html_options = {}, &block)
html_options, name = name, nil if name.is_a?(Hash)
html_options = (html_options || {}).stringify_keys
extras = %w{ cc bcc body subject reply_to }.map! { |item|
option = html_options.delete(item).presence || next
"#{item.dasherize}=#{ERB::Util.url_encode(option)}"
}.compact
extras = extras.empty? ? "" : "?" + extras.join("&")
encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
content_tag("a", name || email_address, html_options, &block)
end Создает ссылку mailto для указанного email_address, которое также используется в качестве текста ссылки, если не задано name. Дополнительные HTML-атрибуты ссылки можно передать в html_options.
Метод mail_to позволяет настроить само электронное письмо, передав специальные ключи в html_options.
Параметры
-
:subject— заранее задает тему письма. -
:body— заранее задает текст письма. -
:cc— добавляет получателей в копию письма. -
:bcc— добавляет получателей в скрытую копию письма. -
:reply_to— заранее задает полеReply-Toписьма.
Маскировка
До Rails 4.0 метод mail_to предоставлял параметры для кодирования адреса с целью затруднить его сбор программами-сканерами электронной почты. Чтобы воспользоваться этими параметрами, установите гем actionview-encoded_mail_to.
Примеры
mail_to "me@domain.com"
# => <a href="mailto:me@domain.com">me@domain.com</a>
mail_to "me@domain.com", "My email"
# => <a href="mailto:me@domain.com">My email</a>
mail_to "me@domain.com", cc: "ccaddress@domain.com",
subject: "This is an example email"
# => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">me@domain.com</a>
Также можно использовать блок, если цель ссылки сложно уместить в параметре name. Например, ERB:
<%= mail_to "me@domain.com" do %>
<strong>Email me:</strong> <span>me@domain.com</span>
<% end %>
# => <a href="mailto:me@domain.com">
<strong>Email me:</strong> <span>me@domain.com</span>
</a> # File actionview/lib/action_view/helpers/url_helper.rb, line 693
def phone_to(phone_number, name = nil, html_options = {}, &block)
html_options, name = name, nil if name.is_a?(Hash)
html_options = (html_options || {}).stringify_keys
country_code = html_options.delete("country_code").presence
country_code = country_code.nil? ? "" : "+#{ERB::Util.url_encode(country_code)}"
encoded_phone_number = ERB::Util.url_encode(phone_number)
html_options["href"] = "tel:#{country_code}#{encoded_phone_number}"
content_tag("a", name || phone_number, html_options, &block)
end Создает ссылку TEL для указанного phone_number. При нажатии на ссылку открывается приложение для звонков по умолчанию, в котором уже указан номер телефона.
Если name не задано, в качестве текста ссылки будет использоваться phone_number.
Поддерживается параметр country_code, который добавляет знак плюса и указанный код страны к номеру телефона в ссылке. Например, country_code: "01" добавит +01 к номеру телефона в ссылке.
Дополнительные HTML-атрибуты ссылки можно передать через html_options.
Параметры
-
:country_code— добавляет код страны к номеру телефона
Примеры
phone_to "1234567890" # => <a href="tel:1234567890">1234567890</a> phone_to "1234567890", "Phone me" # => <a href="tel:1234567890">Phone me</a> phone_to "1234567890", country_code: "01" # => <a href="tel:+011234567890">1234567890</a>
Также можно использовать блок, если цель ссылки сложно уместить в параметре name. Пример ERB:
<%= phone_to "1234567890" do %>
<strong>Phone me:</strong>
<% end %>
# => <a href="tel:1234567890">
<strong>Phone me:</strong>
</a> # File actionview/lib/action_view/helpers/url_helper.rb, line 642
def sms_to(phone_number, name = nil, html_options = {}, &block)
html_options, name = name, nil if name.is_a?(Hash)
html_options = (html_options || {}).stringify_keys
country_code = html_options.delete("country_code").presence
country_code = country_code ? "+#{ERB::Util.url_encode(country_code)}" : ""
body = html_options.delete("body").presence
body = body ? "?&body=#{ERB::Util.url_encode(body)}" : ""
encoded_phone_number = ERB::Util.url_encode(phone_number)
html_options["href"] = "sms:#{country_code}#{encoded_phone_number};#{body}"
content_tag("a", name || phone_number, html_options, &block)
end Создает SMS-ссылку для указанного phone_number. При нажатии на ссылку открывается приложение для отправки SMS по умолчанию, готовое отправить сообщение на указанный номер телефона. Если задан параметр body, текст сообщения будет заранее установлен в body.
Если name не задано, в качестве текста ссылки будет использоваться phone_number.
Поддерживается параметр country_code, который добавляет знак плюса и указанный код страны к номеру телефона в ссылке. Например, country_code: "01" добавит +01 к номеру телефона в ссылке.
Дополнительные HTML-атрибуты ссылки можно передать через html_options.
Параметры
-
:country_code— добавляет код страны к номеру телефона. -
:body— заранее задает текст сообщения.
Примеры
sms_to "5155555785" # => <a href="sms:5155555785;">5155555785</a> sms_to "5155555785", country_code: "01" # => <a href="sms:+015155555785;">5155555785</a> sms_to "5155555785", "Text me" # => <a href="sms:5155555785;">Text me</a> sms_to "5155555785", body: "I have a question about your product." # => <a href="sms:5155555785;?body=I%20have%20a%20question%20about%20your%20product">5155555785</a>
Также можно использовать блок, если цель ссылки сложно уместить в параметре name. Пример ERB:
<%= sms_to "5155555785" do %>
<strong>Text me:</strong>
<% end %>
# => <a href="sms:5155555785;">
<strong>Text me:</strong>
</a>
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.