Home > Enterprise >  Multiple layouts in Ruby on Rails
Multiple layouts in Ruby on Rails

Time:12-01

I have a project where each page needs to import an extra css or JS file for only that page. Is it a good practise to use a different layout file for each view? (I don't want my view files to contain references to css/JS files).

I mean i can have a different layout for each view but i don't know if it is the optimal way to do it.

CodePudding user response:

Best strategy:

Don't worry about it and just let your app handle this for you. Minified CSS and JS file delivery isn't really that slow/big and Rails will compile your assets into single files in production.


If you're determined, it is possible (your mileage may vary depending on your Rails version, and usage of Sprockets or Webpacker)

And you'll really want to understand the Rails asset pipeline (for your version of Rails) before you go nerfing these settings.

CSS inclusion/exclusion

You can ignore the asset pipeline and manually choose which CSS files to include, but you'll need to be diligent about doing this everywhere.

In your app/views/layouts/application.html file, you have a line like this inside the <head> tag:

<%= stylesheet_link_tag 'application', media: 'all' ... %>

This is loading application.css, which is a compiled version of app/assets/stylesheets/application.css and will include all CSS from all other files inside app/assets/stylesheets

Depending on your version of Rails, you'll need to turn off asset pre-compilation in either config/initializers/production.rb or config/initializers/assets.rb:

Rails.application.config.assets.precompile = []

Warning: this will turn off ALL asset compilation, including JS. Be sure you have a strategy to re-include JS files (based upon your asset pipeline)

You will now need to implement some logic to handle what CSS is included when. This could be in app/helpers/application_helper.rb. It could use the view helper [controller_name], (https://apidock.com/rails/ActionController/Metal/controller_name/class), for example, to determine which page you are on and fetch the correct CSS file.

Really rough example:

# app/helpers/application_helper.rb

module ApplicationHelper
  def css_file_chooser
     "/app/assets/stylesheets/#{controller_name}.css"
  end
end

Then in your application.html file, you can do something like this:

<head>
  <%= stylesheet_link_tag css_file_chooser, media: 'all' ... %>
 ...
</head>

The catch here is you'd need to have your specific CSS files named according to your controllers. E.g. if controller_name returns 'posts', you'd need to have a file: 'app/assets/stylesheets/posts.css'

If you do have some site-wide CSS that needs to be applied, you'd need to include a second stylesheet_link_tag:

In this case, if you put all your global styles into app/assets/stylesheets/global.css:

<head>
  <%= stylesheet_link_tag 'global', media: 'all' ... %>
  <%= stylesheet_link_tag css_file_chooser, media: 'all' ... %>
 ...
</head>

JS inclusion/exclusion

It's a bit dusty, but this article outlines a strategy that only loads a JS function or file if the <body> has certain class tags. I used to use it on my Rails 4 and 5 projects.

  • Related