module ActionView::Helpers::AssetUrlHelper

def asset_path(source, options = {})

asset_path("foo.css", skip_pipeline: true, extname: ".js") # => "/foo.css.js"
asset_path("foo", skip_pipeline: true, extname: ".js") # => "/foo.js"

- An extension name can be specified manually with extname.

asset_path("foo.js", skip_pipeline: true) # => "http://assets.example.com/foo.js"
Rails.application.config.action_controller.asset_host = "assets.example.com"

this is commonly used in conjunction with a CDN.
- A different asset host can be specified via config.action_controller.asset_host

asset_path("foo.js", skip_pipeline: true) # => "bar/foo.js"
Rails.application.config.relative_url_root = "bar"

root prepended.
- If config.relative_url_root is specified, all assets will have that

asset_path("") # => ""

asset pipeline and all other behavior described.
- All blank strings will be returned immediately. This bypasses the

asset_path("/foo.png") # => "/foo.png"

URLs and will not be expanded. This will bypass the asset pipeline.
- All assets that begin with a forward slash are assumed to be full

asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js"

asset pipeline and all other behavior described.
- All fully qualified URLs are returned immediately. This bypasses the

using the asset pipeline.
Below lists scenarios that apply to +asset_path+ whether or not you're

=== Options applying to all assets

asset_path("application", type: :stylesheet, skip_pipeline: true) # => "/stylesheets/application.css"
asset_path("application", type: :javascript, skip_pipeline: true) # => "/javascripts/application.js"
asset_path("filedoesnotexist.png", skip_pipeline: true) # => "filedoesnotexist.png"
asset_path("application.js", skip_pipeline: true) # => "application.js"

and that the file exists on disk.
checking is done to verify the source passed into +asset_path+ is valid
Accepts a type option that can specify the asset's extension. No error

=== Without the asset pipeline (skip_pipeline: true)

asset_path("application.js", host: 'example.com', protocol: 'https') # => "https://example.com/assets/application.js"
asset_path('application.js', host: 'example.com') # => "//example.com/assets/application.js"
asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"

which is implemented by asset pipeline gems.
All options passed to +asset_path+ will be passed to +compute_asset_path+

=== With the asset pipeline

All other asset *_path helpers delegate through this method.

skip_pipeline: true to the options.
behavior is "enhanced". You can bypass the asset pipeline by passing in
When using an asset pipeline gem (e.g. propshaft or sprockets-rails), the
This is the entry point for all assets.
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

def asset_url(source, options = {})


asset_url "application.js", host: "http://cdn.example.com" # => http://cdn.example.com/assets/application.js
asset_url "application.js" # => http://example.com/assets/application.js

All other options provided are forwarded to +asset_path+ call.

+config.action_controller.asset_host+ setting.
will be the same. If +:host+ options is set, it overwrites global
will use +asset_path+ internally, so most of their behaviors
Computes the full URL to an asset in the public directory. This
def asset_url(source, options = {})
  path_to_asset(source, options.merge(protocol: :request))
end

def audio_path(source, options = {})

audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
audio_path("/sounds/horse.wav") # => /sounds/horse.wav
audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
audio_path("horse.wav") # => /audios/horse.wav
audio_path("horse") # => /audios/horse

Used internally by +audio_tag+ to build the audio path.
Full paths from the document root will be passed through.
Computes the path to an audio asset in the public audios directory.
def audio_path(source, options = {})
  path_to_asset(source, { type: :audio }.merge!(options))
end

def audio_url(source, options = {})


audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/audios/horse.wav

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +audio_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +audio_path+ internally, so most of their behaviors will be the same.
Computes the full URL to an audio asset in the public audios directory.
def audio_url(source, options = {})
  url_to_asset(source, { type: :audio }.merge!(options))
end

def compute_asset_extname(source, options = {})

nothing should be added.
Compute extname to append to asset path. Returns +nil+ if
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

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

(proc or otherwise).
or the value returned from invoking call on an object responding to call
numbers 0-3 if it contains %d (the number is the source hash mod 4),
the host if no wildcard is set, the host interpolated with the
Pick an asset host for this source. Returns +nil+ if no host is set,
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

def compute_asset_path(source, options = {})

or generate digested paths or query strings.
extensions can override this method to point to custom assets
Computes asset path to public directory. Plugins and
def compute_asset_path(source, options = {})
  dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
  File.join(dir, source)
end

def font_path(source, options = {})

font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
font_path("/dir/font.ttf") # => /dir/font.ttf
font_path("dir/font.ttf") # => /fonts/dir/font.ttf
font_path("font.ttf") # => /fonts/font.ttf
font_path("font") # => /fonts/font

Full paths from the document root will be passed through.
Computes the path to a font asset.
def font_path(source, options = {})
  path_to_asset(source, { type: :font }.merge!(options))
end

def font_url(source, options = {})


font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/fonts/font.ttf

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +font_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +font_path+ internally, so most of their behaviors will be the same.
Computes the full URL to a font asset.
def font_url(source, options = {})
  url_to_asset(source, { type: :font }.merge!(options))
end

def image_path(source, options = {})

plugin authors are encouraged to do so.
The alias +path_to_image+ is provided to avoid that. \Rails uses the alias internally, and
If you have images as application resources this method may conflict with their named routes.

image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
image_path("/icons/edit.png") # => "/icons/edit.png"
image_path("icons/edit.png") # => "/assets/icons/edit.png"
image_path("edit.png") # => "/assets/edit.png"
image_path("edit") # => "/assets/edit"

Used internally by +image_tag+ to build the image path:
Full paths from the document root will be passed through.
Computes the path to an image asset.
def image_path(source, options = {})
  path_to_asset(source, { type: :image }.merge!(options))
end

def image_url(source, options = {})


image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/assets/edit.png

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +image_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +image_path+ internally, so most of their behaviors will be the same.
Computes the full URL to an image asset.
def image_url(source, options = {})
  url_to_asset(source, { type: :image }.merge!(options))
end

def javascript_path(source, options = {})

javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
javascript_path "dir/xmlhr.js" # => /assets/dir/xmlhr.js
javascript_path "xmlhr" # => /assets/xmlhr.js

Used internally by +javascript_include_tag+ to build the script path.
Full paths from the document root will be passed through.
If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
Computes the path to a JavaScript asset in the public javascripts directory.
def javascript_path(source, options = {})
  path_to_asset(source, { type: :javascript }.merge!(options))
end

def javascript_url(source, options = {})


javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/js/xmlhr.js

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +javascript_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +javascript_path+ internally, so most of their behaviors will be the same.
Computes the full URL to a JavaScript asset in the public javascripts directory.
def javascript_url(source, options = {})
  url_to_asset(source, { type: :javascript }.merge!(options))
end

def stylesheet_path(source, options = {})

stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
stylesheet_path "/dir/style.css" # => /dir/style.css
stylesheet_path "dir/style.css" # => /assets/dir/style.css
stylesheet_path "style" # => /assets/style.css

Used internally by +stylesheet_link_tag+ to build the stylesheet path.
Full paths from the document root will be passed through.
If the +source+ filename has no extension, .css will be appended (except for explicit URIs).
Computes the path to a stylesheet asset in the public stylesheets directory.
def stylesheet_path(source, options = {})
  path_to_asset(source, { type: :stylesheet }.merge!(options))
end

def stylesheet_url(source, options = {})


stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/assets/css/style.css

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +stylesheet_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
Computes the full URL to a stylesheet asset in the public stylesheets directory.
def stylesheet_url(source, options = {})
  url_to_asset(source, { type: :stylesheet }.merge!(options))
end

def video_path(source, options = {})

video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
video_path("/trailers/hd.avi") # => /trailers/hd.avi
video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
video_path("hd.avi") # => /videos/hd.avi
video_path("hd") # => /videos/hd

Used internally by +video_tag+ to build the video path.
Full paths from the document root will be passed through.
Computes the path to a video asset in the public videos directory.
def video_path(source, options = {})
  path_to_asset(source, { type: :video }.merge!(options))
end

def video_url(source, options = {})


video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/videos/hd.avi

options is set, it overwrites global +config.action_controller.asset_host+ setting.
Since +video_url+ is based on +asset_url+ method you can set +:host+ options. If +:host+
This will use +video_path+ internally, so most of their behaviors will be the same.
Computes the full URL to a video asset in the public videos directory.
def video_url(source, options = {})
  url_to_asset(source, { type: :video }.merge!(options))
end