Action View 资源 URL 辅助方法¶ ↑
此模块提供生成资源路径和 URL 的方法。
image_path("rails.png") # => "/assets/rails.png" image_url("rails.png") # => "http://www.example.com/assets/rails.png"
使用资源主机¶ ↑
默认情况下,Rails 会在公共文件夹中链接到当前主机上的这些资源,但您可以通过在应用程序配置中设置 ActionController::Base.asset_host 来指示 Rails 从专用的资源服务器链接到资源,这通常在 config/environments/production.rb 中进行。例如,您可以将 assets.example.com 定义为您的资源主机,在环境特定配置文件或 config/application.rb 的 configure 块中进行设置。
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”、“...”、“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 到单个资源主机。您可以从您的 ISP 处阅读更多关于设置 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" )
- 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) 时,行为会被“增强”。您可以通过向 options 传递 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 的 source 是否有效以及文件是否存在于磁盘上进行错误检查。
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"
来源:显示 | 在 GitHub 上
# 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 audios 目录中音频资源的完整 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
来源:显示 | 在 GitHub 上
# 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。
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
为该 source 选择一个资源主机。如果没有设置主机,则返回 nil;如果没有设置通配符,则返回主机;如果包含 %d,则返回与数字 0-3 结合后的主机(数字是 source 的哈希值 mod 4);或者返回调用响应 call 的对象(proc 或其他)所返回的值。
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算到公共目录的资源路径。插件和扩展可以覆盖此方法以指向自定义资源或生成带指纹的路径或查询字符串。
来源:显示 | 在 GitHub 上
# 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
来源:显示 | 在 GitHub 上
# 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
来源:显示 | 在 GitHub 上
# 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 内部使用此别名,并鼓励插件作者也这样做。
来源:显示 | 在 GitHub 上
# 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 javascripts 目录中 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 javascripts 目录中 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
来源:显示 | 在 GitHub 上
# 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
stylesheet_path(source, options = {}) 链接
计算公共 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 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
来源:显示 | 在 GitHub 上
# 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
video_path(source, options = {}) 链接
计算公共 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
来源:显示 | 在 GitHub 上
# 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 = {}) 链接
计算公共 videos 目录中视频资源的完整 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
来源:显示 | 在 GitHub 上
# 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