ChatGPT解决这个技术问题 Extra ChatGPT

Rails layouts per action?

I use a different layout for some actions (mostly for the new action in most of the controllers).

I am wondering what the best way to specify the layout would be? (I am using 3 or more different layouts in the same controller)

I don't like using

render :layout => 'name'

I liked doing

layout 'name', :only => [:new]

But I can't use that to specify 2 or more different layouts.

For example:

When I call layout 2 times in the same controller, with different layout names and different only options, the first one gets ignored - those actions don't display in the layout I specified.

Note: I'm using Rails 2.

The Rails Guides documentation: guides.rubyonrails.org/…
Good point. The documentation for Rails 2: guides.rubyonrails.org/v2.3.11/…
(Also, I posted the guide to help future readers. I have no doubt you had your problem solved a long time ago ;-)

A
August Lilleaas

You can use a method to set the layout.

class MyController < ApplicationController
  layout :resolve_layout

  # ...

  private

  def resolve_layout
    case action_name
    when "new", "create"
      "some_layout"
    when "index"
      "other_layout"
    else
      "application"
    end
  end
end

Cool, thanks. And in case someone wants to do simpler things with one-liner the following is possible. Its easy to read and place in top of the controller. --- layout Proc.new{ ['index', 'new', 'create'].include?(action_name) ? 'some_layout' : 'other_layout' }
Would this have a large effect on application performance if various layouts are using say several different css & js files respectively?
-1: Too complex. The comment below (stackoverflow.com/a/21203783/285154) is the best option.
Thanks! This is still a problem in Rails 4.2, perhaps only if you are using inheriting controllers in many levels. I have used method before, but wasn't thinking of testing that when I had the problem now, thanks again.
@dimitko no it's not, I already referenced that solution in the question itself. It does not work if you want to use 3 or more different layouts (as is exactly my case).
N
Nathan Hinchey

If you are only selecting between two layouts, you can use :only:

class ProductsController < ApplicationController
   layout "admin", only: [:new, :edit]
end

or

class ProductsController < ApplicationController
   layout "application", only: [:index]
end

Well, the problem with this is that you cannot access objects such as current_user to conditionally determine the layout
@AndrewK Dynamically choosing a layout doesn't seem to be part of the question asked.
If any of you read the question you would know this is not the right answer, as I have already described this solution in the question itself and also why it does not work in my case (3 or more layouts).
Like mrbrdo said, this is not the answer. His question specifically indicates (I am using 3 or more different layouts in the same controller). This answer allows a layout and no layout, not different layouts.
G
Gavin Terrill

You can specify the layout for an individual action using respond_to:

  def foo
    @model = Bar.first
    respond_to do |format|
      format.html {render :layout => 'application'}
    end
  end

To me this is the more flexible answer. DRYing things out by applying layout "[...]" to the controller class only allows one statement effectively. If you have more than two layouts to deal with (say, admin, generic_app, tailored_app), you will experience Render and/or redirect were called multiple times in this action` errors; and you have no choice but to use this suggestion.
This answer is the best, its simple and neat as opposed to using methods with switch or if statements inside.
also it can specify the erb file and layout both: format.html { render 'custom_index', layout: 'application' } in the same way.
T
Tunaki

You can also specify the layout for action using render:

def foo
  render layout: "application"
end

b
barelyknown

There's a gem (layout_by_action) for that :)

layout_by_action [:new, :create] => "some_layout", :index => "other_layout"

https://github.com/barelyknown/layout_by_action


p
puneet18

Various ways to specify layout under controller:

In following code, application_1 layout is called under index and show action of Users controller and application layout(default layout) is called for other actions. class UsersController < ApplicationController layout "application_1", only: [:index, :show] end In following code, application_1 layout is called for all action of Users controller. class UsersController < ApplicationController layout "application_1" end In following code, application_1 layout is called for test action of Users controllers only and for all other action application layout(default) is called. class UsersController < ApplicationController def test render layout: "application_1" end end


G
Gregdebrick

Precision :

A not really but working DRY way is what you see above, but with a precision : the layout need to be after your variables for working ("@some"). As :

def your_action
   @some = foo
   render layout: "your_layout"
end

And not :

def your_action
   render layout: "your_layout"
   @some = foo
   @foo = some
end

If you do a before_action... it's won't work also.

Hope it helps.


r
ramzieus

You can use it like my example:

def show
...
render layout: "empty",template: "admin/orders/print" if params.key?('print')
end

I specified the layout and the template html.erb if params print present.