Rails diseños por acción?

165

Utilizo un diseño diferente para algunas acciones (principalmente para la nueva acción en la mayoría de los controladores).

Me pregunto cuál sería la mejor manera de especificar el diseño. (Estoy usando 3 o más diseños diferentes en el mismo controlador)

No me gusta usar

render: layout => 'nombre'

Me gustaba hacer

diseño 'nombre',: solo => [: nuevo]

Pero no puedo usar eso para especificar 2 o más diseños diferentes.

Por ejemplo:

Cuando llamo al diseño 2 veces en el mismo controlador, con diferentes nombres de diseño y diferentes opciones, la primera se ignora: esas acciones no se muestran en el diseño que especifiqué.

Nota: estoy usando Rails 2.

mrbrdo
fuente
1
Documentación de The Rails Guides: guides.rubyonrails.org/…
Kevin
1
Buen punto. La documentación para Rails 2: guides.rubyonrails.org/v2.3.11/…
Kevin
2
(Además, publiqué la guía para ayudar a futuros lectores. No tengo dudas de que tu problema se resolvió hace mucho tiempo ;-)
Kevin

Respuestas:

297

Puede usar un método para establecer el diseño.

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
fuente
22
Genial, gracias. Y en caso de que alguien quiera hacer cosas más simples con una sola línea, lo siguiente es posible. Es fácil de leer y colocar en la parte superior del controlador. ---layout Proc.new{ ['index', 'new', 'create'].include?(action_name) ? 'some_layout' : 'other_layout' }
holli
1
¿Tendría esto un gran efecto en el rendimiento de la aplicación si se utilizan varios diseños, por ejemplo, varios archivos css y js diferentes, respectivamente?
Noz
15
-1: demasiado complejo. El comentario a continuación ( stackoverflow.com/a/21203783/285154 ) es la mejor opción.
dimitarvp
¡Gracias! Esto sigue siendo un problema en Rails 4.2, quizás solo si está utilizando controladores heredados en muchos niveles. He usado el método antes, pero no estaba pensando en probar eso cuando tuve el problema ahora, gracias de nuevo.
244an
@dimitko no, no lo es, ya hice referencia a esa solución en la pregunta misma. No funciona si desea utilizar 3 o más diseños diferentes (como es exactamente mi caso).
mrbrdo
201

Si solo selecciona entre dos diseños, puede usar :only:

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

o

class ProductsController < ApplicationController
   layout "application", only: [:index]
end
axeltaglia
fuente
2
Bueno, el problema con esto es que no puede acceder a objetos como current_user para determinar condicionalmente el diseño
Andrew K
@AndrewK Elegir dinámicamente un diseño no parece ser parte de la pregunta que se hace.
Nick
11
Si alguno de ustedes lee la pregunta, sabría que esta no es la respuesta correcta, ya que ya he descrito esta solución en la pregunta misma y también por qué no funciona en mi caso (3 o más diseños).
mrbrdo
2
Como dijo Mrbrdo, esta no es la respuesta. Su pregunta indica específicamente (I am using 3 or more different layouts in the same controller). Esta respuesta permite un diseño y ningún diseño, no diseños diferentes.
Michael
49

Puede especificar el diseño para una acción individual usando respond_to :

  def foo
    @model = Bar.first
    respond_to do |format|
      format.html {render :layout => 'application'}
    end
  end
Gavin Terrill
fuente
Para mí esta es la respuesta más flexible. SECAR las cosas 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 Renderizar y / o redirigir se llamó varias veces en los errores de esta acción; y no tienes más remedio que usar esta sugerencia.
Jerome
1
Esta respuesta es la mejor, es simple y ordenada en lugar de usar métodos con switch o if declaraciones dentro.
kev
También puede especificar tanto el archivo erb como el diseño: format.html { render 'custom_index', layout: 'application' } de la misma manera.
thatway_3
12

También puede especificar el diseño para la acción usando render:

def foo
  render layout: "application"
end
Yottanami
fuente
7

Varias formas de especificar el diseño bajo el controlador:

  1. En el siguiente código, el diseño de la aplicación_1 se llama bajo índice y muestra la acción del controlador de Usuarios y el diseño de la aplicación (diseño predeterminado) se llama para otras acciones.

    class UsersController < ApplicationController
      layout "application_1", only: [:index, :show]
    end
  2. En el siguiente código, se llama al diseño application_1 para todas las acciones del controlador de Usuarios.

    class UsersController < ApplicationController
       layout "application_1"
    end
  3. En el siguiente código, el diseño de la aplicación_1 se llama solo para la acción de prueba de los controladores de Usuarios y para el resto del diseño de la aplicación de acción (predeterminado).

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

Precisión:

Lo que ves arriba es una forma SECA no realmente funcional pero funcional, pero con precisión: el diseño debe estar detrás de tus variables para trabajar ("@some"). Como :

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

Y no :

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

Si haces una before_action ... tampoco funcionará.

Espero eso ayude.

Gregdebrick
fuente