module ActionView::Helpers::AssetTagHelper
def audio_tag(*sources)
audio_tag(user.name_pronunciation_audio)
Active Storage blobs (audios that are uploaded by the users of your app):
# =>
audio_tag("sound.wav", "sound.mid")
# =>
audio_tag("sound.wav", autoplay: true, controls: true)
# =>
audio_tag("sound.wav")
# =>
audio_tag("sound")
parameter.
When the last parameter is a hash you can add HTML attributes using that
directory, or Active Storage attachments.
+sources+ can be full paths, files that exist in your public audios
tag with nested source tags for each source will be returned. The
a single audio tag will be returned. If +sources+ is an array, an audio
Returns an HTML audio tag for the +sources+. If +sources+ is a string,
def audio_tag(*sources) multiple_sources_tag_builder("audio", sources) 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(:json)
# =>
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
using the +url_options+. You can modify the LINK tag itself in +tag_options+.
:atom, or :json. Control the link options in url_for format
an RSS, Atom, or JSON feed. The +type+ can be :rss (default),
Returns a link tag that browsers and feed readers can use to auto-detect
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {}) if !(type == :rss || type == :atom || type == :json) && tag_options[:type].blank? raise ArgumentError.new("You should pass :type tag_option key explicitly, because you have passed #{type} type other than :rss, :atom, or :json.") end tag( "link", "rel" => tag_options[:rel] || "alternate", "type" => tag_options[:type] || Template::Types[type].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 check_for_image_tag_errors(options)
def check_for_image_tag_errors(options) if options[:size] && (options[:height] || options[:width]) raise ArgumentError, "Cannot pass a :size option with a :height or :width option" end end
def extract_dimensions(size)
def extract_dimensions(size) size = size.to_s if /\A\d+(?:\.\d+)?x\d+(?:\.\d+)?\z/.match?(size) size.split("x") elsif /\A\d+(?:\.\d+)?\z/.match?(size) [size, size] 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 iOS device.
Mobile Safari looks for a different link tag, pointing to an image that
# =>
favicon_link_tag 'myicon.ico'
# =>
favicon_link_tag
respectively:
to override their defaults, "icon" and "image/x-icon"
defaults to "favicon.ico", and also supports +:rel+ and +:type+ options
The helper gets the name of the favicon file as first argument, which
using this helper to generate its corresponding link tag.
their favicon storing the file under app/assets/images, and
To have better control applications may let the asset pipeline manage
request succeeds. If the favicon changes it is hard to get it updated.
ask for /favicon.ico automatically, and cache the file if the
If a page has no link like the one generated by this helper, browsers
Returns a link tag for a favicon managed by the asset pipeline.
def favicon_link_tag(source = "favicon.ico", options = {}) tag("link", { rel: "icon", type: "image/x-icon", href: path_to_image(source, skip_pipeline: options.delete(:skip_pipeline)) }.merge!(options.symbolize_keys)) end
def image_tag(source, options = {})

image_tag(user.avatar.variant(resize_to_limit: [100, 100]), size: '100')
# =>

image_tag(user.avatar.variant(resize_to_limit: [100, 100]))
# =>

image_tag(user.avatar)
Active Storage blobs (images that are uploaded by the users of your app):
# =>

image_tag("pic.jpg", srcset: [["pic_1024.jpg", "1024w"], ["pic_1980.jpg", "1980w"]], sizes: "100vw")
# =>

image_tag("icon.png", srcset: { "icon_2x.png" => "2x", "icon_4x.png" => "4x" })
# =>

image_tag("/icons/icon.gif", data: { title: 'Rails Application' })
# =>

image_tag("/icons/icon.gif", class: "menu_icon")
# =>

image_tag("/icons/icon.gif", height: '32', width: '32')
# =>

image_tag("/icons/icon.gif", size: "16")
# =>

image_tag("icon.png", size: "16x10", alt: "Edit Entry")
# =>

image_tag("icon.png")
# =>
image_tag("icon")
Assets (images that are part of your app):
==== Examples
pairs, each image path will be expanded before the list is formatted as a string.
* :srcset - If supplied as a hash or array of [source, descriptor]
:size will be ignored if the value is not in the correct format.
width="30" height="45", and "50" becomes width="50" height="50".
* :size - Supplied as "#{width}x#{height}" or "#{number}", so "30x45" becomes
additional keys for convenience and conformance:
You can add HTML attributes using the +options+. The +options+ supports
==== Options
path, a file, or an Active Storage attachment.
Returns an HTML image tag for the +source+. The +source+ can be a full
def image_tag(source, options = {}) options = options.symbolize_keys check_for_image_tag_errors(options) skip_pipeline = options.delete(:skip_pipeline) options[:src] = resolve_asset_source("image", source, skip_pipeline) if options[:srcset] && !options[:srcset].is_a?(String) options[:srcset] = options[:srcset].map do |src_path, size| src_path = path_to_image(src_path, skip_pipeline: skip_pipeline) "#{src_path} #{size}" end.join(", ") end options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size] options[:loading] ||= image_loading if image_loading options[:decoding] ||= image_decoding if image_decoding tag("img", options) end
def javascript_include_tag(*sources)
javascript_include_tag "http://www.example.com/xmlhr.js", defer: true
# =>
javascript_include_tag "http://www.example.com/xmlhr.js", async: true
# =>
javascript_include_tag "http://www.example.com/xmlhr.js", nonce: true
# =>
javascript_include_tag "http://www.example.com/xmlhr.js"
# =>
javascript_include_tag "http://www.example.com/xmlhr"
#
# =>
javascript_include_tag "common.javascript", "/elsewhere/cools"
# =>
javascript_include_tag "xmlhr.js"
# =>
javascript_include_tag "template.jst", extname: false
# =>
javascript_include_tag "xmlhr", host: "localhost", protocol: "https"
# =>
javascript_include_tag "xmlhr"
==== Examples
{MDN docs}[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script].
options affect the tag, please refer to the
For more information regarding how the :async and :defer
+script+ tag.
Any other specified options will be treated as HTML attributes for the
for the script. Defaults to +true+.
* :nopush - Specify if the use of server push is not desired
sending the Preload Links header.
be executed after the document has been parsed. Additionally, prevents
attribute, which indicates to the browser that the script is meant to
* :defer - When set to +true+, adds the +defer+ HTML
and evaluated as soon as possible.
attribute, allowing the script to be fetched in parallel to be parsed
* :async - When set to +true+, adds the +async+ HTML
you have Content Security Policy enabled.
* :nonce - When set to true, adds an automatic nonce value if
when it is set to true.
* :skip_pipeline - This option is used to bypass the asset pipeline
that path.
* :host - When a relative URL is provided the host is added to the
applies when a relative URL and +host+ options are provided.
* :protocol - Sets the protocol of the generated URL. This option only
already exists. This only applies for relative URLs.
* :extname - Append an extension to the generated URL unless the extension
parameter. This includes but is not limited to the following options:
When the last parameter is a hash you can add HTML attributes using that
==== Options
to the assets.
enabled, \Rails will push a 103 Early Hints response that links
If the server supports HTTP Early Hints, and the +defer+ option is not
source, and include other JavaScript or CoffeeScript files inside the manifest.
When the Asset Pipeline is enabled, you can pass the name of your manifest as
last argument.
You can modify the HTML attributes of the script tag by passing a hash as the
appended to the path extname: false can be set on the options.
When passing paths, the ".js" extension is optional. If you do not want ".js"
root. Relative paths are idiomatic, use absolute paths only when needed.
to assets/javascripts, full paths are assumed to be relative to the document
Sources may be paths to JavaScript files. Relative paths are assumed to be relative
Returns an HTML script tag for each of the +sources+ provided.
def javascript_include_tag(*sources) options = sources.extract_options!.stringify_keys path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys preload_links = [] use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header") nopush = options["nopush"].nil? ? true : options.delete("nopush") crossorigin = options.delete("crossorigin") crossorigin = "anonymous" if crossorigin == true integrity = options["integrity"] rel = options["type"] == "module" || options["type"] == :module ? "modulepreload" : "preload" sources_tags = sources.uniq.map { |source| href = path_to_javascript(source, path_options) if use_preload_links_header && !options["defer"] && href.present? && !href.start_with?("data:") preload_link = "<#{href}>; rel=#{rel}; as=script" preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil? preload_link += "; integrity=#{integrity}" unless integrity.nil? preload_link += "; nopush" if nopush preload_links << preload_link end tag_options = { "src" => href, "crossorigin" => crossorigin }.merge!(options) if tag_options["nonce"] == true tag_options["nonce"] = content_security_policy_nonce end content_tag("script", "", tag_options) }.join("\n").html_safe if use_preload_links_header send_preload_links_header(preload_links) end sources_tags end
def multiple_sources_tag_builder(type, sources)
def multiple_sources_tag_builder(type, sources) options = sources.extract_options!.symbolize_keys skip_pipeline = options.delete(:skip_pipeline) sources.flatten! yield options if block_given? if sources.size > 1 content_tag(type, options) do safe_join sources.map { |source| tag("source", src: resolve_asset_source(type, source, skip_pipeline)) } end else options[:src] = resolve_asset_source(type, sources.first, skip_pipeline) content_tag(type, nil, options) end end
def picture_tag(*sources, &block)

picture_tag(user.profile_picture)
Active Storage blobs (images that are uploaded by the users of your app):
# =>

picture_tag { tag(:source, :srcset => image_path("picture-small.webp"), :media => "(min-width: 600px)") + tag(:source, :srcset => image_path("picture-big.webp")) + image_tag("picture.png", :alt => "Image") }
# =>

picture_tag(:class => "my-class") { tag(:source, :srcset => image_path("picture.webp")) + image_tag("picture.png", :alt => "Image") }
# =>

picture_tag(["picture.webp", "picture.png"], :image => { alt: "Image" })
# =>

picture_tag("picture.webp", "picture.png", :image => { alt: "Image" })
# =>

picture_tag("picture.webp", "picture.png")
# =>

picture_tag("gold.png", :image => { :size => "45x70" })
# =>

picture_tag("gold.png", :image => { :size => "20" })
# =>

picture_tag("picture.webp")
==== Examples
* :image - Hash of options that are passed directly to the +image_tag+ helper.
parameter. Apart from all the HTML supported options, the following are supported:
When the last parameter is a hash you can add HTML attributes using that
==== Options
will populate the contents of the tag accordingly.
For complete control over the picture tag, a block can be passed, which
an img tag, the last element you provide will be used for the img tag.
directory, or Active Storage attachments. Since the picture tag requires
+sources+ can be full paths, files that exist in your public images
tag with nested source tags for each source will be returned. The
a single picture tag will be returned. If +sources+ is an array, a picture
Returns an HTML picture tag for the +sources+. If +sources+ is a string,
def picture_tag(*sources, &block) sources.flatten! options = sources.extract_options!.symbolize_keys image_options = options.delete(:image) || {} skip_pipeline = options.delete(:skip_pipeline) content_tag("picture", options) do if block.present? capture(&block).html_safe elsif sources.size <= 1 image_tag(sources.last, image_options) else source_tags = sources.map do |source| tag("source", srcset: resolve_asset_source("image", source, skip_pipeline), type: Template::Types[File.extname(source)[1..]]&.to_s) end safe_join(source_tags << image_tag(sources.last, image_options)) end end end
def preload_link_tag(source, options = {})
# =>
preload_link_tag("/media/audio.ogg", nopush: true)
# =>
preload_link_tag("//example.com/font.woff2", crossorigin: "use-credentials")
# =>
preload_link_tag("//example.com/font.woff2")
# =>
preload_link_tag("worker.js", as: "worker")
# =>
preload_link_tag(post_path(format: :json), as: "fetch")
# =>
preload_link_tag("/videos/video.webm")
# =>
preload_link_tag("custom_theme.css")
==== Examples
* :integrity - Specify the integrity attribute.
* :nopush - Specify if the use of server push is not desired for the resource. Defaults to +false+.
* :crossorigin - Specify the crossorigin attribute, required to load cross-origin resources.
* :as - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type.
* :type - Override the auto-generated mime type, defaults to the mime type for +source+ extension.
==== Options
a full path, or an URI.
The +source+ can be the path of a resource managed by asset pipeline,
Returns a link tag that browsers can use to preload the +source+.
def preload_link_tag(source, options = {}) href = path_to_asset(source, skip_pipeline: options.delete(:skip_pipeline)) extname = File.extname(source).downcase.delete(".") mime_type = options.delete(:type) || Template::Types[extname]&.to_s as_type = options.delete(:as) || resolve_link_as(extname, mime_type) crossorigin = options.delete(:crossorigin) crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font") integrity = options[:integrity] nopush = options.delete(:nopush) || false rel = mime_type == "module" || mime_type == :module ? "modulepreload" : "preload" link_tag = tag.link( rel: rel, href: href, as: as_type, type: mime_type, crossorigin: crossorigin, **options.symbolize_keys) preload_link = "<#{href}>; rel=#{rel}; as=#{as_type}" preload_link += "; type=#{mime_type}" if mime_type preload_link += "; crossorigin=#{crossorigin}" if crossorigin preload_link += "; integrity=#{integrity}" if integrity preload_link += "; nopush" if nopush send_preload_links_header([preload_link]) link_tag end
def resolve_asset_source(asset_type, source, skip_pipeline)
def resolve_asset_source(asset_type, source, skip_pipeline) if source.is_a?(Symbol) || source.is_a?(String) path_to_asset(source, type: asset_type.to_sym, skip_pipeline: skip_pipeline) else polymorphic_url(source) end rescue NoMethodError => e raise ArgumentError, "Can't resolve #{asset_type} into URL: #{e}" end
def resolve_link_as(extname, mime_type)
def resolve_link_as(extname, mime_type) case extname when "js" then "script" when "css" then "style" when "vtt" then "track" else mime_type.to_s.split("/").first.presence_in(%w(audio video font image)) end end
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE) return if preload_links.empty? response_present = respond_to?(:response) && response return if response_present && response.sending? if respond_to?(:request) && request request.send_early_hints("link" => preload_links.join(",")) end if response_present header = +response.headers["link"].to_s preload_links.each do |link| break if header.bytesize + link.bytesize > max_header_size if header.empty? header << link else header << "," << link end end response.headers["link"] = header end end
def stylesheet_link_tag(*sources)
stylesheet_link_tag "style", nonce: true
#
# =>
stylesheet_link_tag "random.styles", "/css/stylish"
# =>
stylesheet_link_tag "style", media: "print"
# =>
stylesheet_link_tag "style", media: "all"
# =>
stylesheet_link_tag "style.less", extname: false, skip_pipeline: true, rel: "stylesheet/less"
# =>
stylesheet_link_tag "http://www.example.com/style.css"
# =>
stylesheet_link_tag "style.css"
# =>
stylesheet_link_tag "style"
==== Examples
for the stylesheet. Defaults to +true+.
* :nopush - Specify if the use of server push is not desired
you have Content Security Policy enabled.
* :nonce - When set to true, adds an automatic nonce value if
when it is set to true.
* :skip_pipeline - This option is used to bypass the asset pipeline
that path.
* :host - When a relative URL is provided the host is added to the
applies when a relative URL and +host+ options are provided.
* :protocol - Sets the protocol of the generated URL. This option only
already exists. This only applies for relative URLs.
* :extname - Append an extension to the generated URL unless the extension
==== Options
Hints response that links to the assets.
If the server supports HTTP Early Hints, \Rails will push a 103 Early
You can modify the link attributes by passing a hash as the last argument.
set extname: false in the options.
If you do not want .css appended to the path,
If you don't specify an extension, .css will be appended automatically.
When passing paths, the .css extension is optional.
Returns a stylesheet link tag for the sources specified as arguments.
def stylesheet_link_tag(*sources) options = sources.extract_options!.stringify_keys path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header") preload_links = [] crossorigin = options.delete("crossorigin") crossorigin = "anonymous" if crossorigin == true nopush = options["nopush"].nil? ? true : options.delete("nopush") integrity = options["integrity"] sources_tags = sources.uniq.map { |source| href = path_to_stylesheet(source, path_options) if use_preload_links_header && href.present? && !href.start_with?("data:") preload_link = "<#{href}>; rel=preload; as=style" preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil? preload_link += "; integrity=#{integrity}" unless integrity.nil? preload_link += "; nopush" if nopush preload_links << preload_link end tag_options = { "rel" => "stylesheet", "crossorigin" => crossorigin, "href" => href }.merge!(options) if tag_options["nonce"] == true tag_options["nonce"] = content_security_policy_nonce end if apply_stylesheet_media_default && tag_options["media"].blank? tag_options["media"] = "screen" end tag(:link, tag_options) }.join("\n").html_safe if use_preload_links_header send_preload_links_header(preload_links) end sources_tags end
def video_tag(*sources)
video_tag(user.intro_video)
Active Storage blobs (videos that are uploaded by the users of your app):
# =>
video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
# =>
video_tag(["trailer.ogg", "trailer.flv"])
# =>
video_tag("trailer.ogg", "trailer.flv")
# =>
video_tag("/trailers/hd.avi", height: '32', width: '32')
# =>
video_tag("/trailers/hd.avi", size: "16")
# =>
video_tag("/trailers/hd.avi", size: "16x16")
# =>
video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true)
# =>
video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png")
# =>
video_tag("trailer.ogg", controls: true, preload: 'none')
# =>
video_tag("trailer.ogg")
# =>
video_tag("trailer")
==== Examples
the :poster option instead using an asset in the public folder.
* :poster_skip_pipeline will bypass the asset pipeline when using
:size will be ignored if the value is not in the correct format.
width="30" height="45", and "50" becomes width="50" height="50".
* :size - Supplied as "#{width}x#{height}" or "#{number}", 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
parameter. The following options are supported:
When the last parameter is a hash you can add HTML attributes using that
==== Options
directory, or Active Storage attachments.
+sources+ can be full paths, files that exist 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 = sources.extract_options!.symbolize_keys public_poster_folder = options.delete(:poster_skip_pipeline) sources << options multiple_sources_tag_builder("video", sources) do |tag_options| tag_options[:poster] = path_to_image(tag_options[:poster], skip_pipeline: public_poster_folder) if tag_options[:poster] tag_options[:width], tag_options[:height] = extract_dimensions(tag_options.delete(:size)) if tag_options[:size] end end