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
  if source[0] != ?/
    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