module ActionView::Helpers::AssetTagHelper
def self.register_javascript_expansion(expansions)
javascript_include_tag :monkey # =>
ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"]
that the plugin installed in public/javascripts.
to be called from plugin initialization to register javascript files
is passed to javascript_include_tag. This method is typically intended
Register one or more javascript files to be included when symbol
def self.register_javascript_expansion(expansions) expansions.each do |key, values| @@javascript_expansions[key] = (@@javascript_expansions[key] || []) | Array(values) end end
def self.register_javascript_include_default(*args)
def self.register_javascript_include_default(*args) ActiveSupport::Deprecation.warn "register_javascript_include_default is deprecated. Please " \ "manipulate config.action_view.javascript_expansions[:defaults] directly", caller self.javascript_expansions[:defaults].concat args end
def self.register_stylesheet_expansion(expansions)
stylesheet_link_tag :monkey # =>
ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"]
that the plugin installed in public/stylesheets.
to be called from plugin initialization to register stylesheet files
is passed to stylesheet_link_tag. This method is typically intended
Register one or more stylesheet files to be included when symbol
def self.register_stylesheet_expansion(expansions) expansions.each do |key, values| @@stylesheet_expansions[key] = (@@stylesheet_expansions[key] || []) | Array(values) end end
def self.reset_javascript_include_default
def self.reset_javascript_include_default ActiveSupport::Deprecation.warn "reset_javascript_include_default is deprecated. Please manipulate " \ "config.action_view.javascript_expansions[:defaults] directly", caller self.javascript_expansions[:defaults] = ['prototype', 'effects', 'dragdrop', 'controls', 'rails'] end
def asset_file_path(path)
def asset_file_path(path) File.join(config.assets_dir, path.split('?').first) end
def asset_file_path!(path)
def asset_file_path!(path) unless is_uri?(path) absolute_path = asset_file_path(path) raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path) return absolute_path end end
def audio_path(source)
audio_path("/sounds/horse.wav") # => /sounds/horse.avi
audio_path("sounds/horse.wav") # => /audios/sounds/horse.avi
audio_path("horse.wav") # => /audios/horse.avi
audio_path("horse") # => /audios/horse
==== Examples
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) compute_public_path(source, 'audios') end
def audio_tag(source, options = {})
audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
audio_tag("sound.wav") # =>
audio_tag("sound") # =>
==== Examples
your public audios directory.
The +source+ can be full path or file that exists in
Returns an html audio tag for the +source+.
def audio_tag(source, options = {}) options.symbolize_keys! options[:src] = path_to_audio(source) tag("audio", options) end
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "Example RSS"}) # =>
auto_discovery_link_tag(:rss, {:controller => "news", :action => "feed"}) # =>
auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
auto_discovery_link_tag(:atom) # =>
auto_discovery_link_tag # =>
==== Examples
* :title - Specify the title of the link, defaults to the +type+
* :type - Override the auto-generated mime type
* :rel - Specify the relation of this link, defaults to "alternate"
==== Options
+url_options+. You can modify the LINK tag itself in +tag_options+.
:atom. Control the link options in url_for format using the
an RSS or ATOM feed. The +type+ can either be :rss (default) or
Returns a link tag that browsers and news readers can use to auto-detect
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {}) tag( "link", "rel" => tag_options[:rel] || "alternate", "type" => tag_options[:type] || Mime::Type.lookup_by_extension(type.to_s).to_s, "title" => tag_options[:title] || type.to_s.upcase, "href" => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options ) end
def collect_asset_files(*path)
def collect_asset_files(*path) dir = path.first Dir[File.join(*path.compact)].collect do |file| file[-(file.size - dir.size - 1)..-1].sub(/\.\w+$/, '') end.sort end
def compute_asset_host(source)
or the value returned from invoking the proc if it's a proc or the value from
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) if host = config.asset_host if host.is_a?(Proc) || host.respond_to?(:call) case host.is_a?(Proc) ? host.arity : host.method(:call).arity when 2 request = controller.respond_to?(:request) && controller.request host.call(source, request) else host.call(source) end else (host =~ /%d/) ? host % (source.hash % 4) : host end end end
def compute_javascript_paths(*args)
def compute_javascript_paths(*args) expand_javascript_sources(*args).collect { |source| compute_public_path(source, 'javascripts', 'js', false) } end
def compute_public_path(source, dir, ext = nil, include_host = true)
roots. Rewrite the asset path for cache-busting asset ids. Include
Prefix with /dir/ if lacking a leading +/+. Account for relative URL
Add the the extension +ext+ if not present. Return full URLs otherwise untouched.
def compute_public_path(source, dir, ext = nil, include_host = true) return source if is_uri?(source) source += ".#{ext}" if rewrite_extension?(source, dir, ext) source = "/#{dir}/#{source}" unless source[0] == ?/ source = rewrite_asset_path(source, config.asset_path) has_request = controller.respond_to?(:request) if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/} source = "#{controller.config.relative_url_root}#{source}" end source = rewrite_host_and_protocol(source, has_request) if include_host source end
def compute_stylesheet_paths(*args)
def compute_stylesheet_paths(*args) expand_stylesheet_sources(*args).collect { |source| compute_public_path(source, 'stylesheets', 'css', false) } end
def determine_source(source, collection)
def determine_source(source, collection) case source when Symbol collection[source] || raise(ArgumentError, "No expansion found for #{source.inspect}") else source end end
def ensure_javascript_sources!(sources)
def ensure_javascript_sources!(sources) sources.each do |source| asset_file_path!(compute_public_path(source, 'javascripts', 'js', false)) end return sources end
def ensure_stylesheet_sources!(sources)
def ensure_stylesheet_sources!(sources) sources.each do |source| asset_file_path!(compute_public_path(source, 'stylesheets', 'css', false)) end return sources end
def expand_javascript_sources(sources, recursive = false)
def expand_javascript_sources(sources, recursive = false) if sources.include?(:all) all_javascript_files = (collect_asset_files(config.javascripts_dir, ('**' if recursive), '*.js') - ['application']) << 'application' ((determine_source(:defaults, @@javascript_expansions).dup & all_javascript_files) + all_javascript_files).uniq else expanded_sources = sources.collect do |source| determine_source(source, @@javascript_expansions) end.flatten expanded_sources << "application" if sources.include?(:defaults) && File.exist?(File.join(config.javascripts_dir, "application.js")) expanded_sources end end
def expand_stylesheet_sources(sources, recursive)
def expand_stylesheet_sources(sources, recursive) if sources.first == :all collect_asset_files(config.stylesheets_dir, ('**' if recursive), '*.css') else sources.collect do |source| determine_source(source, @@stylesheet_expansions) end.flatten end end
def favicon_link_tag(source='/favicon.ico', options={})
<%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %>
The following call would generate such a tag:
will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad.
For example, Mobile Safari looks for a different LINK tag, pointing to an image that
The helper accepts an additional options hash where you can override "rel" and "type".
That's passed to +path_to_image+ as is, so it gives
<%= favicon_link_tag 'favicon.ico' %>
You may specify a different file in the first argument:
generates
<%= favicon_link_tag %>
won't see the update. Using this helper prevents that because it appends an asset ID:
root of your application and it changes later, clients that have it in their cache
Web browsers cache favicons. If you just throw a favicon.ico into the document
def favicon_link_tag(source='/favicon.ico', options={}) tag('link', { :rel => 'shortcut icon', :type => 'image/vnd.microsoft.icon', :href => path_to_image(source) }.merge(options.symbolize_keys)) end
def image_path(source)
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.railsapplication.com/img/edit.png") # => "http://www.railsapplication.com/img/edit.png"
image_path("/icons/edit.png") # => "/icons/edit.png"
image_path("icons/edit.png") # => "/images/icons/edit.png"
image_path("edit.png") # => "/images/edit.png"
image_path("edit") # => "/images/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 in the public images directory.
def image_path(source) compute_public_path(source, 'images') end
def image_tag(source, options = {})

image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>

image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
image_tag("/icons/icon.gif", :class => "menu_icon") # =>
image_tag("/icons/icon.gif", :height => '32', :width => '32') # =>
image_tag("/icons/icon.gif", :size => "16x16") # =>
image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
image_tag("icon.png") # =>
image_tag("icon") # =>
==== Examples
This can be used to implement an easy image toggle that fires on onmouseover.
event is fired, and sets the original image to be replaced onmouseout.
* :mouseover - Set an alternate image to be used when the onmouseover
value is not in the correct format.
width="30" and height="45". :size will be ignored if the
* :size - Supplied as "{Width}x{Height}", so "30x45" becomes
+source+ is used (capitalized and without the extension)
* :alt - If no alt text is given, the file name part of the
three additional keys for convenience and conformance:
You can add HTML attributes using the +options+. The +options+ supports
==== Options
path or a file that exists in your public images directory.
Returns an html image tag for the +source+. The +source+ can be a full
def image_tag(source, options = {}) options.symbolize_keys! src = options[:src] = path_to_image(source) unless src =~ /^cid:/ options[:alt] = options.fetch(:alt){ File.basename(src, '.*').capitalize } end if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} end if mouseover = options.delete(:mouseover) options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'" options[:onmouseout] = "this.src='#{src}'" end tag("img", options) end
def is_uri?(path)
def is_uri?(path) path =~ %r{^[-a-z]+://|^cid:} end
def javascript_include_tag(*sources)
The :recursive option is also available for caching:
javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is true =>
javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is false =>
javascript_include_tag :all, :cache => true # when config.perform_caching is true =>
...
javascript_include_tag :all, :cache => true # when config.perform_caching is false =>
==== Examples
environment).
is set to true (which is the case by default for the Rails production environment, but not for the development
compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching
You can also cache multiple javascripts into one file, which requires less HTTP connections to download and can better be
== Caching multiple javascripts into one
javascript_include_tag :all, :recursive => true
If you want Rails to search in all the subdirectories under javascripts, you should explicitly set :recursive:
all subsequently included files.
Note that the default javascript files will be included first. So Prototype and Scriptaculous are available to
...
javascript_include_tag :all # =>
You can also include all javascripts in the javascripts directory using :all as the source:
(e.g., you're going to be using a certain .js file in every action), then take a look at the register_javascript_include_default method.
Though it's not really recommended practice, if you need to extend the default JavaScript set for any reason
* = The application.js file is only referenced if it exists
...
javascript_include_tag :defaults # =>
javascript_include_tag "http://www.railsapplication.com/xmlhr.js" # =>
javascript_include_tag "http://www.railsapplication.com/xmlhr" # =>
javascript_include_tag "common.javascript", "/elsewhere/cools" # =>
javascript_include_tag "xmlhr.js" # =>
javascript_include_tag "xmlhr" # =>
==== Examples
html attributes of the script tag by passing a hash as the last argument.
javascripts directory, it will be included as well. You can modify the
:defaults, if an application.js file exists in your public
your application, pass :defaults as the source. When using
root. To include the Prototype and Scriptaculous javascript libraries in
current page or you can pass the full path relative to your document
that exist in your public/javascripts directory for inclusion into the
can pass in the filename (.js extension is optional) of javascript files
Returns an html script tag for each of the +sources+ provided. You
def javascript_include_tag(*sources) options = sources.extract_options!.stringify_keys concat = options.delete("concat") cache = concat || options.delete("cache") recursive = options.delete("recursive") if concat || (config.perform_caching && cache) joined_javascript_name = (cache == true ? "all" : cache) + ".js" joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.javascripts_dir, joined_javascript_name) unless config.perform_caching && File.exists?(joined_javascript_path) write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) end javascript_src_tag(joined_javascript_name, options) else sources = expand_javascript_sources(sources, recursive) ensure_javascript_sources!(sources) if cache sources.collect { |source| javascript_src_tag(source, options) }.join("\n").html_safe end end
def javascript_path(source)
javascript_path "http://www.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr
javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
javascript_path "xmlhr" # => /javascripts/xmlhr.js
==== Examples
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) compute_public_path(source, 'javascripts', 'js') end
def javascript_src_tag(source, options)
def javascript_src_tag(source, options) content_tag("script", "", { "type" => Mime::JS, "src" => path_to_javascript(source) }.merge(options)) end
def join_asset_file_contents(paths)
def join_asset_file_contents(paths) paths.collect { |path| File.read(asset_file_path!(path)) }.join("\n\n") end
def rails_asset_id(source)
Use the RAILS_ASSET_ID environment variable or the source's
def rails_asset_id(source) if asset_id = ENV["RAILS_ASSET_ID"] asset_id else if @@cache_asset_timestamps && (asset_id = @@asset_timestamps_cache[source]) asset_id else path = File.join(config.assets_dir, source) asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : '' if @@cache_asset_timestamps @@asset_timestamps_cache_guard.synchronize do @@asset_timestamps_cache[source] = asset_id end end asset_id end end end
def rewrite_asset_path(source, path = nil)
Break out the asset path rewrite in case plugins wish to put the asset id
def rewrite_asset_path(source, path = nil) if path && path.respond_to?(:call) return path.call(source) elsif path && path.is_a?(String) return path % [source] end asset_id = rails_asset_id(source) if asset_id.blank? source else source + "?#{asset_id}" end end
def rewrite_extension?(source, dir, ext)
def rewrite_extension?(source, dir, ext) source_ext = File.extname(source)[1..-1] ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(config.assets_dir, dir, "#{source}.#{ext}")))) end
def rewrite_host_and_protocol(source, has_request)
def rewrite_host_and_protocol(source, has_request) host = compute_asset_host(source) if has_request && host.present? && !is_uri?(host) host = "#{controller.request.protocol}#{host}" end "#{host}#{source}" end
def stylesheet_link_tag(*sources)
stylesheet_link_tag :all, :concat => true
you have too many stylesheets for IE to load.
To force concatenation (even in development mode) set :concat to true. This is useful if
stylesheet_link_tag :all, :cache => true, :recursive => true
The :recursive option is also available for caching:
stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is true =>
stylesheet_link_tag "shop", "cart", "checkout", :cache => "payment" # when config.perform_caching is false =>
stylesheet_link_tag :all, :cache => true # when config.perform_caching is true =>
stylesheet_link_tag :all, :cache => true # when config.perform_caching is false =>
==== Examples
environment). Examples:
is set to true (which is the case by default for the Rails production environment, but not for the development
compressed by gzip (leading to faster transfers). Caching will only happen if config.perform_caching
You can also cache multiple stylesheets into one file, which requires less HTTP connections and can better be
== Caching multiple stylesheets into one
stylesheet_link_tag :all, :recursive => true
If you want Rails to search in all the subdirectories under stylesheets, you should explicitly set :recursive:
stylesheet_link_tag :all # =>
You can also include all styles in the stylesheets directory using :all as the source:
stylesheet_link_tag "random.styles", "/css/stylish" # =>
stylesheet_link_tag "style", :media => "print" # =>
stylesheet_link_tag "style", :media => "all" # =>
stylesheet_link_tag "http://www.railsapplication.com/style.css" # =>
stylesheet_link_tag "style.css" # =>
stylesheet_link_tag "style" # =>
==== Examples
You can modify the link attributes by passing a hash as the last argument.
you don't specify an extension, .css will be appended automatically.
Returns a stylesheet link tag for the sources specified as arguments. If
def stylesheet_link_tag(*sources) options = sources.extract_options!.stringify_keys concat = options.delete("concat") cache = concat || options.delete("cache") recursive = options.delete("recursive") if concat || (config.perform_caching && cache) joined_stylesheet_name = (cache == true ? "all" : cache) + ".css" joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? config.assets_dir : config.stylesheets_dir, joined_stylesheet_name) unless config.perform_caching && File.exists?(joined_stylesheet_path) write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) end stylesheet_tag(joined_stylesheet_name, options) else sources = expand_stylesheet_sources(sources, recursive) ensure_stylesheet_sources!(sources) if cache sources.collect { |source| stylesheet_tag(source, options) }.join("\n").html_safe end end
def stylesheet_path(source)
stylesheet_path "http://www.railsapplication.com/css/style" # => http://www.railsapplication.com/css/style
stylesheet_path "/dir/style.css" # => /dir/style.css
stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
stylesheet_path "style" # => /stylesheets/style.css
==== Examples
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) compute_public_path(source, 'stylesheets', 'css') end
def stylesheet_tag(source, options)
def stylesheet_tag(source, options) tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => html_escape(path_to_stylesheet(source)) }.merge(options), false, false) end
def video_path(source)
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
==== Examples
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) compute_public_path(source, 'videos') end
def video_tag(sources, options = {})
video_tag(["trailer.ogg", "trailer.flv"] :size => "160x120") # =>
video_tag(["trailer.ogg", "trailer.flv"]) # =>
video_tag("/trailers/hd.avi", :height => '32', :width => '32') # =>
video_tag("/trailers/hd.avi", :size => "16x16") # =>
video_tag("trailer.m4v", :size => "16x10", :poster => "screenshot.png") # =>
video_tag("trailer.ogg", :controls => true, :autobuffer => true) # =>
video_tag("trailer.ogg") # =>
video_tag("trailer") # =>
==== Examples
value is not in the correct format.
width="30" and height="45". :size will be ignored if the
* :size - Supplied as "{Width}x{Height}", so "30x45" becomes
before the video loads. The path is calculated like the +src+ of +image_tag+.
* :poster - Set an image (like a screenshot) to be shown
two additional keys for convenience and conformance:
You can add HTML attributes using the +options+. The +options+ supports
==== Options
directory.
+sources+ can be full paths or files that exists in your public videos
tag with nested source tags for each source will be returned. The
a single video tag will be returned. If +sources+ is an array, a video
Returns an html video tag for the +sources+. If +sources+ is a string,
def video_tag(sources, options = {}) options.symbolize_keys! options[:poster] = path_to_image(options[:poster]) if options[:poster] if size = options.delete(:size) options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$} end if sources.is_a?(Array) content_tag("video", options) do sources.map { |source| tag("source", :src => source) }.join.html_safe end else options[:src] = path_to_video(sources) tag("video", options) end end
def write_asset_file_contents(joined_asset_path, asset_paths)
def write_asset_file_contents(joined_asset_path, asset_paths) FileUtils.mkdir_p(File.dirname(joined_asset_path)) File.atomic_write(joined_asset_path) { |cache| cache.write(join_asset_file_contents(asset_paths)) } # Set mtime to the latest of the combined files to allow for # consistent ETag without a shared filesystem. mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max File.utime(mt, mt, joined_asset_path) end