module ActionView::Helpers::AssetUrlHelper
Помощники URL ресурсов Action View
Этот модуль предоставляет методы для создания путей и URL ресурсов.
image_path("rails.png")
# => "/assets/rails.png"
image_url("rails.png")
# => "http://www.example.com/assets/rails.png"
Использование хостов ресурсов
По умолчанию Rails ссылается на эти ресурсы на текущем хосте в общедоступной папке, однако вы можете указать Rails обращаться к ресурсам с выделенного сервера ресурсов, задав ActionController::Base.asset_host в конфигурации приложения, обычно в config/environments/production.rb. Например, можно определить assets.example.com в качестве хоста ресурсов следующим образом — внутри блока configure файлов конфигурации для конкретного окружения или в config/application.rb:
config.action_controller.asset_host = "assets.example.com"
Helpers учитывают это:
image_tag("rails.png")
# => <img src="http://assets.example.com/assets/rails.png" />
stylesheet_link_tag("application")
# => <link href="http://assets.example.com/assets/application.css" rel="stylesheet" />
Браузеры открывают ограниченное количество одновременных соединений с одним хостом. Точное число зависит от браузера и его версии. Это ограничение может привести к тому, что загрузка некоторых ресурсов будет ожидать завершения загрузки предыдущих ресурсов. Чтобы распределить запросы между четырьмя хостами, можно использовать подстановочный знак %d в asset_host. Например, assets%d.example.com распределит запросы ресурсов между «assets0.example.com», …, «assets3.example.com».
image_tag("rails.png")
# => <img src="http://assets0.example.com/assets/rails.png" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/assets/application.css" rel="stylesheet" />
Это может повысить скорость загрузки ресурсов в вашем приложении. Также возможно, что сочетание дополнительных накладных расходов на соединение (DNS, SSL) и общих ограничений браузера на количество соединений приведёт к замедлению работы. Обязательно измерьте реальную производительность в целевых браузерах до и после этого изменения.
Для настройки соответствующих хостов можно создать четыре настоящих хоста или использовать подстановочный DNS, чтобы создать CNAME-запись, направляющую подстановочный знак на один сервер ресурсов. Подробнее о настройке DNS-записей CNAME можно узнать у своего интернет-провайдера.
Примечание: это исключительно оптимизация производительности браузера, а не способ балансировки нагрузки сервера. Общие сведения см. на странице www.die.net/musings/page_load_time/, а данные об ограничениях на количество соединений — на странице www.browserscope.org/?category=network.
Также можно управлять хостом ресурсов более гибко, задав asset_host как proc, например:
ActionController::Base.asset_host = Proc.new { |source|
"http://assets#{OpenSSL::Digest::SHA256.hexdigest(source).to_i(16) % 2 + 1}.example.com"
}
image_tag("rails.png")
# => <img src="http://assets1.example.com/assets/rails.png" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/assets/application.css" rel="stylesheet" />
Приведённый выше пример генерирует «assets1.example.com» и «assets2.example.com». Этот параметр полезен, например, если вам нужно меньше или больше четырёх хостов, собственные имена хостов и т. д.
Как видно, proc принимает параметр source. Это строка с абсолютным путём к ресурсу, например «/assets/rails.png».
ActionController::Base.asset_host = Proc.new { |source|
if source.end_with?('.css')
"http://stylesheets.example.com"
else
"http://assets.example.com"
end
}
image_tag("rails.png")
# => <img src="http://assets.example.com/assets/rails.png" />
stylesheet_link_tag("application")
# => <link href="http://stylesheets.example.com/assets/application.css" rel="stylesheet" />
Также можно указать второй параметр request. Он особенно полезен для обслуживания ресурсов со страницы, защищённой SSL. Приведённый ниже proc отключает хостинг ресурсов для HTTPS-соединений, но продолжает отправлять ресурсы с хостов ресурсов для обычных HTTP-запросов. Если у вас нет сертификатов SSL для каждого хоста ресурсов, этот способ позволяет избежать предупреждений клиента о смешанном содержимом. Обратите внимание, что параметр request может быть не передан, например, при предварительной компиляции ресурсов командой bin/rails assets:precompile. Используйте Proc вместо lambda, поскольку Proc допускает отсутствие параметров и задаёт им значение nil.
config.action_controller.asset_host = Proc.new { |source, request|
if request && request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
"#{request.protocol}assets.example.com"
end
}
Также можно реализовать собственный объект хоста ресурсов, который отвечает на call и принимает один или два параметра, как и proc.
config.action_controller.asset_host = AssetHostingWithMinimumSsl.new( "http://asset%d.example.com", "https://asset1.example.com" )
Константы
- ASSET_EXTENSIONS
- ASSET_PUBLIC_DIRECTORIES
-
Сопоставляет типы ресурсов с общедоступными каталогами.
- URI_REGEXP
Открытые методы экземпляра
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 187
def asset_path(source, options = {})
raise ArgumentError, "nil is not a valid asset source" if source.nil?
source = source.to_s
return "" if source.blank?
return source if URI_REGEXP.match?(source)
tail, source = source[/([?#].+)$/], source.sub(/([?#].+)$/, "")
if extname = compute_asset_extname(source, options)
source = "#{source}#{extname}"
end
unless source.start_with?(?/)
if options[:skip_pipeline]
source = public_compute_asset_path(source, options)
else
source = compute_asset_path(source, options)
end
end
relative_url_root = defined?(config.relative_url_root) && config.relative_url_root
if relative_url_root
source = File.join(relative_url_root, source) unless source.start_with?("#{relative_url_root}/")
end
if host = compute_asset_host(source, options)
source = File.join(host, source)
end
"#{source}#{tail}"
end Это точка входа для всех ресурсов. При использовании гемов конвейера ресурсов (например, propshaft или sprockets-rails) поведение «расширяется». Передав skip_pipeline: true в параметры, можно обойти конвейер ресурсов.
Все остальные помощники *_path для ресурсов делегируют вызов этому методу.
С конвейером ресурсов
Все параметры, переданные в asset_path, будут переданы в compute_asset_path, реализуемый гемами конвейера ресурсов.
asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
asset_path('application.js', host: 'example.com') # => "//example.com/assets/application.js"
asset_path("application.js", host: 'example.com', protocol: 'https') # => "https://example.com/assets/application.js"
Без конвейера ресурсов (skip_pipeline: true)
Принимает параметр type, который может указывать расширение ресурса. Проверка ошибок не выполняется: не проверяется, является ли источник, переданный в asset_path, допустимым и существует ли файл на диске.
asset_path("application.js", skip_pipeline: true) # => "application.js"
asset_path("filedoesnotexist.png", skip_pipeline: true) # => "filedoesnotexist.png"
asset_path("application", type: :javascript, skip_pipeline: true) # => "/javascripts/application.js"
asset_path("application", type: :stylesheet, skip_pipeline: true) # => "/stylesheets/application.css"
Параметры, применяемые ко всем ресурсам
Ниже перечислены сценарии, применимые к asset_path независимо от того, используете ли вы конвейер ресурсов.
-
Все полные URL возвращаются немедленно. Это обходит конвейер ресурсов и все описанное ниже поведение.
asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js" -
Все ресурсы, начинающиеся с косой черты, считаются полными URL и не преобразуются. Это обходит конвейер ресурсов.
asset_path("/foo.png") # => "/foo.png" -
Все пустые строки возвращаются немедленно. Это обходит конвейер ресурсов и все описанное ниже поведение.
asset_path("") # => "" -
Если указан
config.relative_url_root, этот корневой путь будет добавлен в начало пути всех ресурсов.Rails.application.config.relative_url_root = "bar" asset_path("foo.js", skip_pipeline: true) # => "bar/foo.js" -
Другой хост ресурсов можно указать с помощью
config.action_controller.asset_host; обычно это используется совместно с CDN.Rails.application.config.action_controller.asset_host = "assets.example.com" asset_path("foo.js", skip_pipeline: true) # => "http://assets.example.com/foo.js" -
Имя расширения можно указать вручную с помощью
extname.asset_path("foo", skip_pipeline: true, extname: ".js") # => "/foo.js" asset_path("foo.css", skip_pipeline: true, extname: ".js") # => "/foo.css.js"
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 231
def asset_url(source, options = {})
path_to_asset(source, options.merge(protocol: :request))
end Вычисляет полный URL ресурса в общедоступном каталоге. Внутри используется asset_path, поэтому большая часть поведения совпадает. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
Все остальные переданные параметры перенаправляются при вызове asset_path.
asset_url "application.js" # => http://example.com/assets/application.js asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 430
def audio_path(source, options = {})
path_to_asset(source, { type: :audio }.merge!(options))
end Вычисляет путь к аудиоресурсу в общедоступном каталоге audios. Полные пути от корня документа передаются без изменений. Используется внутри audio_tag для формирования пути к аудио.
audio_path("horse") # => /audios/horse
audio_path("horse.wav") # => /audios/horse.wav
audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
audio_path("/sounds/horse.wav") # => /sounds/horse.wav
audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 442
def audio_url(source, options = {})
url_to_asset(source, { type: :audio }.merge!(options))
end Вычисляет полный URL аудиоресурса в общедоступном каталоге audios. Внутри используется audio_path, поэтому большая часть поведения совпадает. Поскольку audio_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/audios/horse.wav
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 243
def compute_asset_extname(source, options = {})
return if options[:extname] == false
extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
if extname && File.extname(source) != extname
extname
else
nil
end
end Вычисляет расширение, добавляемое к пути ресурса. Возвращает nil, если добавлять ничего не нужно.
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 277
def compute_asset_host(source = "", options = {})
request = self.request if respond_to?(:request)
host = options[:host]
host ||= config.asset_host if defined? config.asset_host
if host
if host.respond_to?(:call)
arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
args = [source]
args << request if request && (arity > 1 || arity < 0)
host = host.call(*args)
elsif host.include?("%d")
host = host % (Zlib.crc32(source) % 4)
end
end
host ||= request.base_url if request && options[:protocol] == :request
return unless host
if URI_REGEXP.match?(host)
host
else
protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
case protocol
when :relative
"//#{host}"
when :request
"#{request.protocol}#{host}"
else
"#{protocol}://#{host}"
end
end
end Выбирает хост ресурсов для указанного источника. Возвращает nil, если хост не задан; возвращает хост, если подстановочный знак не задан; подставляет в хост числа от 0 до 3, если он содержит %d (число определяется как хеш источника по модулю 4); либо возвращает значение, полученное при вызове объекта, отвечающего на call (proc или другого).
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 266
def compute_asset_path(source, options = {})
dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
File.join(dir, source)
end Вычисляет путь к ресурсу в общедоступном каталоге. Плагины и расширения могут переопределить этот метод, чтобы указывать на пользовательские ресурсы или создавать пути с дайджестами либо строками запроса.
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 455
def font_path(source, options = {})
path_to_asset(source, { type: :font }.merge!(options))
end Вычисляет путь к ресурсу шрифта. Полные пути от корня документа передаются без изменений.
font_path("font") # => /fonts/font
font_path("font.ttf") # => /fonts/font.ttf
font_path("dir/font.ttf") # => /fonts/dir/font.ttf
font_path("/dir/font.ttf") # => /dir/font.ttf
font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 467
def font_url(source, options = {})
url_to_asset(source, { type: :font }.merge!(options))
end Вычисляет полный URL ресурса шрифта. Внутри используется font_path, поэтому большая часть поведения совпадает. Поскольку font_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/fonts/font.ttf
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 378
def image_path(source, options = {})
path_to_asset(source, { type: :image }.merge!(options))
end Вычисляет путь к ресурсу изображения. Полные пути от корня документа передаются без изменений. Используется внутри image_tag для формирования пути к изображению:
image_path("edit") # => "/assets/edit"
image_path("edit.png") # => "/assets/edit.png"
image_path("icons/edit.png") # => "/assets/icons/edit.png"
image_path("/icons/edit.png") # => "/icons/edit.png"
image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
Если изображения являются ресурсами приложения, этот метод может конфликтовать с именованными маршрутами. Чтобы избежать этого, предусмотрен псевдоним path_to_image. Rails использует этот псевдоним внутри, и разработчикам плагинов рекомендуется поступать так же.
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 390
def image_url(source, options = {})
url_to_asset(source, { type: :image }.merge!(options))
end Вычисляет полный URL ресурса изображения. Внутри используется image_path, поэтому большая часть поведения совпадает. Поскольку image_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/assets/edit.png
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 321
def javascript_path(source, options = {})
path_to_asset(source, { type: :javascript }.merge!(options))
end Вычисляет путь к ресурсу JavaScript в общедоступном каталоге javascripts. Если у имени файла source нет расширения, будет добавлено .js (кроме явных URI). Полные пути от корня документа передаются без изменений. Используется внутри javascript_include_tag для формирования пути к скрипту.
javascript_path "xmlhr" # => /assets/xmlhr.js javascript_path "dir/xmlhr.js" # => /assets/dir/xmlhr.js javascript_path "/dir/xmlhr" # => /dir/xmlhr.js javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 333
def javascript_url(source, options = {})
url_to_asset(source, { type: :javascript }.merge!(options))
end Вычисляет полный URL ресурса JavaScript в общедоступном каталоге javascripts. Внутри используется javascript_path, поэтому большая часть поведения совпадает. Поскольку javascript_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/js/xmlhr.js
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 348
def stylesheet_path(source, options = {})
path_to_asset(source, { type: :stylesheet }.merge!(options))
end Вычисляет путь к ресурсу таблицы стилей в общедоступном каталоге stylesheets. Если у имени файла source нет расширения, будет добавлено .css (кроме явных URI). Полные пути от корня документа передаются без изменений. Используется внутри stylesheet_link_tag для формирования пути к таблице стилей.
stylesheet_path "style" # => /assets/style.css stylesheet_path "dir/style.css" # => /assets/dir/style.css stylesheet_path "/dir/style.css" # => /dir/style.css stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 360
def stylesheet_url(source, options = {})
url_to_asset(source, { type: :stylesheet }.merge!(options))
end Вычисляет полный URL ресурса таблицы стилей в общедоступном каталоге stylesheets. Внутри используется stylesheet_path, поэтому большая часть поведения совпадает. Поскольку stylesheet_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/assets/css/style.css
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 404
def video_path(source, options = {})
path_to_asset(source, { type: :video }.merge!(options))
end Вычисляет путь к видеоресурсу в общедоступном каталоге videos. Полные пути от корня документа передаются без изменений. Используется внутри video_tag для формирования пути к видео.
video_path("hd") # => /videos/hd
video_path("hd.avi") # => /videos/hd.avi
video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
video_path("/trailers/hd.avi") # => /trailers/hd.avi
video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
# File actionview/lib/action_view/helpers/asset_url_helper.rb, line 416
def video_url(source, options = {})
url_to_asset(source, { type: :video }.merge!(options))
end Вычисляет полный URL видеоресурса в общедоступном каталоге videos. Внутри используется video_path, поэтому большая часть поведения совпадает. Поскольку video_url основан на методе asset_url, можно задать параметры :host. Если задан параметр :host, он переопределяет глобальную настройку config.action_controller.asset_host.
video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/videos/hd.avi
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.