0

Using multiple layout statements in Rails will throw an error. Rails ignores all but the last layout statement.

However, I have a complicated layout system where I need to dynamically render several different layouts other than the standard application layout (the layout option in a controller allows for just one alternative layout, the rest defaulting to app/layouts/application.html.erb). I was hoping the following would be a good substitute:

In this case, I'm using a static_controller.rb to render the following static content pages (about.html.erb, contact.html.erb, careers.html.erb, help.html.erb, home.html.erb, landing.html.erb, legal.html.erb, and policies.html.erb).

  1. landing.html.erb will have a custom, full-page layout with no header or footer.
  2. about, contact, home, and legal will each follow the "main" layout [app/views/layouts/main.html.erb].
  3. careers, help, and policies will each follow the "not_main" layout [app/views/layouts/not_main.html.erb].

I need something similar to this in the target controller:

class StaticController < ApplicationController
...
layout 'full', :only => [:landing]

%w[about contact home legal ].each do |static_page|
  layout 'main'
end

%w[careers help policies].each do |static_page|
  layout 'not_main'
end
...
def about
end
...
end #Closes the Static Controller

This would be preferable to setting the layout in each action call. However, Rails continues to ignore the previous layout statements, even though they are wrapped in a %w array. Any ideas how to make something like this work?

Matteo
  • 1,136
  • 1
  • 16
  • 36
  • probably better to set the layout as an option on the render for each method, e.g. `render layout: "main"` when rendering the view for the methods about, contact, home and legal, etc. – Les Nightingill Jul 24 '22 at 14:48
  • That kinda violates the DRY principle. I was hoping to modularize the code as much as possible. What I can't figure out is why both arrays are being evaluated when only one has its condition met. – Matteo Jul 24 '22 at 14:52

2 Answers2

1
class StaticController < ApplicationController
  layout 'full', only: [:landing]
  layout 'main', only: [:about, :contact, :home, :legal]
  layout  'not_main', only: [:careers, :help, :policies]

  .....
end
  • This is the format that I had in a previous version of Rails, but it no longer works. Rails ignores the previous `layout` statements and only parses the last one. In this scenario, `landing`, `about`, `contact`, `home`, and `legal` would all be ignored and default to the `application.html.erb` template. – Matteo Jul 25 '22 at 20:52
0

This works for me on Rails7:

class StaticController < ApplicationController

  layout :select_layout

private
  def select_layout
    "main" if %w[about contact home legal].include? action_name
    "full" if %w[landing].include? action_name
    # ...etc
  end

end

Les Nightingill
  • 5,662
  • 1
  • 29
  • 32