"/assets/rails.png" image_url("rails."> "/assets/rails.png" image_url("rails."> 跳至内容 跳至搜索

Action View 资产 URL 帮助器

此模块提供生成资产路径和 URL 的方法。

image_path("rails.png")
# => "/assets/rails.png"

image_url("rails.png")
# => "http://www.example.com/assets/rails.png"

使用资产主机

默认情况下,Rails 在 public 文件夹中的当前主机上链接到这些资产,但可以通过在应用程序配置中设置 ActionController::Base.asset_host 将 Rails 引导至从专用资产服务器链接到资产,通常在 config/environments/production.rb 中。例如,您将定义 assets.example.com 作为您的资产主机,方法是在环境特定配置文件或 config/application.rbconfigure 块中。

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" />

浏览器对单个主机的并发连接数有限。确切数字因浏览器和版本而异。此限制可能会导致某些资产下载等待之前的资产完成才能开始。您可以在 asset_host 中使用 %d 通配符将请求分配到四个主机。例如,assets%d.example.com 将资产请求分布在“assets0.example.com”、“assets1.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)和整体浏览器连接限制的组合会导致此解决方案变慢。您应该确保在更改之前和之后跨目标浏览器测量您的实际性能。

要实现相应的 host,您可以设置四个实际 host 或使用通配符 DNS 将通配符 CNAME 到单个资产 host。您可以从您的 ISP 了解更多有关设置您的 DNS CNAME 记录的信息。

注意:这纯粹是浏览器性能优化,不适用于服务器负载均衡。请参阅 www.die.net/musings/page_load_time/ 以获取背景信息,并参阅 www.browserscope.org/?category=network 以获取连接限制数据。

或者,您可以通过将 asset_host 设置为类似这样的过程来对资产主机施加更多控制

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”。此选项很有用,例如,如果您需要少于/多于四个主机、自定义主机名等。

正如您所见,该过程需要一个 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 保护的页面提供资源特别有用。下面的示例过程禁用了 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"
)
方法
A
C
F
I
J
P
S
U
V

常量

ASSET_EXTENSIONS = { javascript: ".js", stylesheet: ".css" }
 
ASSET_PUBLIC_DIRECTORIES = { audio: "/audios", font: "/fonts", image: "/images", javascript: "/javascripts", stylesheet: "/stylesheets", video: "/videos" }
 

将资源类型映射到公共目录。

URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i
 

实例公共方法

asset_path(source, options = {})

这是所有资源的入口点。当使用资源管道 gem(例如 propshaft 或 sprockets-rails)时,行为会“增强”。您可以通过在选项中传入 skip_pipeline: true 来绕过资源管道。

所有其他资源 *_path 帮助器通过此方法委派。

使用资源管道

传递给 asset_path 的所有选项都将传递给 compute_asset_path,后者由资源管道 gem 实现。

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"
    
别名:path_to_asset
# 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

asset_url(source, options = {})

计算公共目录中资产的完整 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
别名:url_to_asset
# 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

audio_path(source, options = {})

计算公共音频目录中音频资源的路径。将从文档根目录传递完整路径。由 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
别名:path_to_audio
# 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

audio_url(source, options = {})

计算公共音频目录中音频资源的完整 URL。这将在内部使用 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
别名:url_to_audio
# 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

compute_asset_extname(source, options = {})

计算要附加到资源路径的扩展名。如果不需要添加任何内容,则返回 nil

# 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

compute_asset_host(source = "", options = {})

为此源选择一个资源主机。如果未设置主机,则返回 nil;如果未设置通配符,则返回主机;如果主机包含 %d,则返回使用 0-3 的数字插值的主机(数字是源哈希模 4),或调用响应调用的对象(过程或其他)返回的值。

# 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

compute_asset_path(source, options = {})

计算公共目录的资产路径。插件和扩展可以覆盖此方法以指向自定义资产或生成摘要路径或查询字符串。

# 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

font_path(source, options = {})

计算字体资产的路径。将传递来自文档根目录的完整路径。

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
别名:path_to_font
# 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_url(source, options = {})

计算字体资产的完整 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
别名:url_to_font
# 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

image_path(source, options = {})

计算图像资产的路径。将传递来自文档根目录的完整路径。由 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 在内部使用别名,鼓励插件作者这样做。

别名:path_to_image
# 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_url(source, options = {})

计算图像资产的完整 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
别名:url_to_image
# 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

javascript_path(source, options = {})

计算公共 JavaScript 目录中 JavaScript 资产的路径。如果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 321
def javascript_path(source, options = {})
  path_to_asset(source, { type: :javascript }.merge!(options))
end

javascript_url(source, options = {})

计算公共 JavaScript 目录中 JavaScript 资产的完整 URL。这将在内部使用 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 333
def javascript_url(source, options = {})
  url_to_asset(source, { type: :javascript }.merge!(options))
end

path_to_asset(source, options = {})

别名:asset_path

path_to_audio(source, options = {})

别名:audio_path

path_to_font(source, options = {})

别名:font_path

path_to_image(source, options = {})

别名:image_path

path_to_javascript(source, options = {})

别名:javascript_path

path_to_stylesheet(source, options = {})

别名:stylesheet_path

path_to_video(source, options = {})

别名:video_path

public_compute_asset_path(source, options = {})

stylesheet_path(source, options = {})

计算公共样式表目录中样式表资产的路径。如果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 348
def stylesheet_path(source, options = {})
  path_to_asset(source, { type: :stylesheet }.merge!(options))
end

stylesheet_url(source, options = {})

计算 public stylesheets 目录中样式表资产的完整 URL。这将在内部使用 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 360
def stylesheet_url(source, options = {})
  url_to_asset(source, { type: :stylesheet }.merge!(options))
end

url_to_asset(source, options = {})

别名:asset_url

url_to_audio(source, options = {})

别名:audio_url

url_to_font(source, options = {})

别名:font_url

url_to_image(source, options = {})

别名:image_url

url_to_javascript(source, options = {})

别名:javascript_url

url_to_stylesheet(source, options = {})

别名:stylesheet_url

url_to_video(source, options = {})

别名:video_url

video_path(source, options = {})

计算公共视频目录中视频资源的路径。将传递来自文档根目录的完整路径。由 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
别名:path_to_video
# 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

video_url(source, options = {})

计算公共视频目录中视频资源的完整 URL。这将在内部使用 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
别名:url_to_video
# 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