Page-specific assets in Rails

A common task that is surprisingly obscure.

A common use-case in web development is including some asset (e.g. a stylesheet or javascript file) only for certain pages. The situation gets trickier if the inclusion has to be in the page header. Finding how do do this in RoR is surprisingly tricky, due to outdated or bad information, but the answer is simple. Successive calls to content-for will append data, so the header can be written something like:

<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<%= javascript_include_tag :defaults %> ... <%= yield :more_head_content %>
</head>

and the view written:

<% content_for :more_head_content do %>
        <%= javascript_include_tag "myfile2" %>
<% end %>
<% content_for :more_head_content do %>
        <%= javascript_include_tag "myfile3" %>
<% end %>

to push both javascript include tags into the header. Two caveats: this will not work in partials. Also, there are some reports of failure in more recent versions of Rails, reason unclear. See Railscasts.

A more fiddly version that may overcome these problems follows. Instead of a symbol, we include an instance variable in the header to later write to:

<head> ... <%= @even_more_head_content %> </head>

In the view that requires the inclusion, write:

<% @even_more_head_content ||= "";
        @even_more_head_content += capture do %>
<%= javascript_include_tag 'myextracode' %> <% end %>

Working through the code, the inclusion variable is initialised if not already. Extra content is then captured and appended to it. "Extra" content may be safely added from several places and will appear in the header. No doubt this could be shortened, if only Ruby would allow pass by reference semantics. A curious site effect is that if you try to include vanilla HTML tags (links, spans, etc.) in the header, they get pushed done into the body of the document and appear at the top of the visible webpage.

Taken from Stack Overflow, although the code as presented there will not work.