Layouts de trilhos por ação?

165

Eu uso um layout diferente para algumas ações (principalmente para a nova ação na maioria dos controladores).

Gostaria de saber qual seria a melhor maneira de especificar o layout? (Estou usando 3 ou mais layouts diferentes no mesmo controlador)

Eu não gosto de usar

render: layout => 'nome'

Eu gostei de fazer

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

Mas não posso usar isso para especificar dois ou mais layouts diferentes.

Por exemplo:

Quando chamo o layout duas vezes no mesmo controlador, com nomes de layout diferentes e opções diferentes, o primeiro é ignorado - essas ações não são exibidas no layout especificado.

Nota: estou usando o Rails 2.

mrbrdo
fonte
1
A documentação dos Guias do Rails: guias.rubyonrails.org/…
Kevin
1
Bom ponto. A documentação para o Rails 2: Guides.rubyonrails.org/v2.3.11/…
Kevin
2
(Além disso, eu postei o guia para ajudar os futuros leitores tenho nenhuma dúvida que você teve seu problema resolvido há muito tempo ;-).
Kevin

Respostas:

297

Você pode usar um método para definir o 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
August Lilleaas
fonte
22
Legal, obrigado. E caso alguém queira fazer coisas mais simples com uma linha, é possível o seguinte. É fácil de ler e colocar em cima do controlador. ---layout Proc.new{ ['index', 'new', 'create'].include?(action_name) ? 'some_layout' : 'other_layout' }
Holli
1
Isso teria um grande efeito no desempenho do aplicativo se vários layouts estiverem usando, digamos, vários arquivos css e js, respectivamente?
Noz
15
-1: muito complexo. O comentário abaixo ( stackoverflow.com/a/21203783/285154 ) é a melhor opção.
dimitarvp
Obrigado! Isso ainda é um problema no Rails 4.2, talvez apenas se você estiver usando controladores herdados em vários níveis. Eu já usei o método antes, mas não estava pensando em testar isso quando tive o problema agora, obrigado novamente.
244 dez
@ Dimitko não, não é, eu já referenciei essa solução na própria pergunta. Não funciona se você deseja usar 3 ou mais layouts diferentes (como é exatamente o meu caso).
Mrbrdo
201

Se você estiver selecionando apenas entre dois layouts, poderá usar :only:

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

ou

class ProductsController < ApplicationController
   layout "application", only: [:index]
end
axeltaglia
fonte
2
Bem, o problema com isto é que você não pode acessar objetos como current_user para determinar condicionalmente o layout
Andrew K
@AndrewK A escolha dinâmica de um layout não parece fazer parte da pergunta.
25416 Nick as
11
Se algum de vocês ler a pergunta, saberá que esta não é a resposta certa, pois eu já descrevi essa solução na própria pergunta e também por que ela não funciona no meu caso (3 ou mais layouts).
Mrbrdo
2
Como o senhor disse, esta não é a resposta. Sua pergunta indica especificamente (I am using 3 or more different layouts in the same controller). Esta resposta permite um layout e nenhum layout, não layouts diferentes.
Michael
49

Você pode especificar o layout para uma ação individual usando respond_to :

  def foo
    @model = Bar.first
    respond_to do |format|
      format.html {render :layout => 'application'}
    end
  end
Gavin Terrill
fonte
Para mim, esta é a resposta mais flexível. Secar as coisas aplicando 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 e / ou redirecionar foram chamados várias vezes nos erros desta ação; e você não tem escolha a não ser usar esta sugestão.
22414 Jerome
1
Esta resposta é a melhor, é simples e elegante, em vez de usar métodos com instruções switch ou if dentro.
Kev
também pode especificar o arquivo erb e o layout: format.html { render 'custom_index', layout: 'application' } da mesma maneira.
thatway_3
12

Você também pode especificar o layout da ação usando render:

def foo
  render layout: "application"
end
yottanami
fonte
7

Várias maneiras de especificar o layout no controlador:

  1. No código a seguir, o layout do aplicativo_1 é chamado no índice e mostra a ação do Controlador de usuários e o layout do aplicativo (layout padrão) é chamado para outras ações.

    class UsersController < ApplicationController
      layout "application_1", only: [:index, :show]
    end
  2. No código a seguir, o layout do aplicativo_1 é chamado para todas as ações do controlador Usuários.

    class UsersController < ApplicationController
       layout "application_1"
    end
  3. No código a seguir, o layout do aplicativo_1 é chamado apenas para a ação de teste dos controladores de usuários e para todos os outros layouts do aplicativo de ação (padrão).

        class UsersController < ApplicationController
          def test
            render layout: "application_1"
          end
        end
puneet18
fonte
5

Precisão:

Uma maneira DRY não muito real, mas que funciona, é o que você vê acima, mas com precisão: o layout precisa seguir suas variáveis ​​para trabalhar ("@algumas"). Como :

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

E não :

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

Se você fizer uma ação antes ... não funcionará também.

Espero que ajude.

Gregdebrick
fonte