Ruby Yagi ๐Ÿ

Ruby, Rails, Web dev articles

Insert page specific CSS or JS using content_for

by Axel Kee 16 November 2020

There might be cases where you want to insert some CSS or JS snippet into a specific page only , for example inserting Stripe JS and CSS only on the payment page, but not on other pages of the same controller.

If you insert the snippet into layout/application.html.erb , it will be available to all the pages, which might slow down the load time of other pages which doesnโ€™t use the script!

<!-- app/views/layout/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    <title>My awesome app</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
      
     <!-- This Stripe script will be available to all pages even if they dont have payment form -->
     <script src="https://js.stripe.com/v3/"></script>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

We can solve this by using a custom yield and content_for function. Before moving to the solution, letโ€™s look at how the โ€œyieldโ€ function works.

Notice the <%= yield %> code in application.html.erb ? This is how our content in index.html.erb get inserted to the layout file :

yield

Solution

We can define a custom yield inside the <head> tag, and only fill in this custom yield on the payment page like this :

<!-- app/views/layout/application.html.erb -->
<!DOCTYPE html>
<html>
  <head>
    <title>My awesome app</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    
    <!-- we can put a custom yield with parameter here -->
    <%= yield(:head) %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

Then in the payment page (payment.html.erb) :

<!-- payment.html.erb -->
<% content_for :head do %>
  <!-- header content specific to this payment page -->
  <script src="https://js.stripe.com/v3/"></script>
<% end %>

  
<h1>Checkout page</h1>
<span>Pls buy my product kthxbye</span>

Hereโ€™s how the final layout is generated :

custom yield layout

You can use multiple custom yield with parameters in header / footer of a page, and use the content_for block to show different content on different pages.

eg : <%= yield :abcd %> will correspond to <% content_for :abcd do %> .

Tired of spending hours to deploy your Rails app to AWS / DigitalOcean / Linode?

Get my automated script that setup Rails server with just one command, and deploy your app with just one command

    โ€‹

    + Weekly ish Web development tips to help you become a better Ruby developer.

    โ€‹

    Unsubscribe any time. We respect your email privacy.

    โ€‹

    References

    Official Rails layout and rendering guides