2009-04-30 24 views
8

Me gustaría poder enviar de una acción de controlador a otra condicionalmente, en base a una combinación de parámetros de consulta y datos en la base de datos.¿Cuál es la forma correcta de ejecutar una acción de controlador desde otra acción de controlador sin una redirección HTTP?

Lo que tengo en este momento es algo así como:

class OldController < ApplicationController 
    def old_controller_action 
    if should_use_new_controller 
     new_params = params.dup 
     new_params[:controller] = "new_controller_action" 
     redirect_to new_params 
     return 
    end 
    # rest of old and busted 
    end 
end 

class NewController < ApplicationController 
    def new_controller_action 
    # new hotness 
    end 
end 

Esto funciona muy bien, pero emite una redirección HTTP, que es lento. Me gustaría poder hacer lo mismo, pero dentro de la misma solicitud HTTP.

¿Hay una manera limpia de hacer esto?

Editar sección: La recompensa se destinará a alguien que me puede mostrar una forma limpia de hacer esto que deja los controladores y sus acciones relativamente intactos (que no sea el código de redirección).

Respuesta

13

En lugar de invocar código a través de acciones, extraiga el código a lib/o algo, y llame a ese código desde ambos controladores.

# lib/foo.rb 
module Foo 
    def self.bar 
    # ... 
    end 
end 

# posts_controller 
def index 
    Foo.bar 
end 

# things_controller 
def index 
    Foo.bar 
end 
+0

Sí, me hubiera ocurrido esto también, aunque no es una opción muy emocionante, desde la perspectiva de la organización del código. –

+1

Es realmente bien, ya que crea en el método denominado de cohesión a partir de dos lugares eso es fácilmente comprobable –

7

crear una instancia de la clase del controlador:

@my_other_controller = MyOtherController.new 

luego llamar a métodos en él:

@my_other_controller.some_method(params[:id]) 

prefiero la idea de módulo, pero esto debe hacer el truco.

+0

Esto no funcionará tan bien. Es difícil llamar al método 'render' dentro de esta nueva instancia de controlador. Si llama a renderizar en el controlador original, perderá todas las variables configuradas en el controlador llamado. – holli

1

sospecho que desea la opción 3, pero deja ir a través de los primeros algunas alternativas

Opción 1 - Empuje la lógica de selección de controlador en un ayudante que se inserta el enlace de la derecha en su vista. Benifits: los controladores permanecen limpios, Contras: si la lógica de decisión depende de los valores enviados, este enfoque no funcionará. Si los sitios web externos llaman a URL, esto no funcionará.

Opción 2 - Inserta la lógica en tu modelo. Pro's: mantiene el controlador limpio. Contras: no funciona bien si tienes muchos sesson, params o render/redirect_to interaction.

Opción 3 - permanecer dentro del mismo controlador. Sospecho que está tratando de reemplazar algunas funcionalidades existentes con alguna funcionalidad nueva, pero solo en algunos casos. Pro's: simple y tiene acceso a todo lo que necesita. Contras: solo funciona si tiene sentido usar el mismo controlador, es decir, si está trabajando con la misma entidad, como usuario, lugar o empresa.

Veamos un ejemplo para la opción 3. Mi controlador de enlaces tiene behavour totalmente diferent para los administradores que otros usuarios ...

class LinksController < ApplicationController 
    #... 

    def new 
    #Check params and db values to make a choice here 
    admin? ? new_admin : new_user 
    end 

    #... 

private 

    def new_admin 
    #All of the good stuff - can use params, flash, etc 
    render :action => 'new_admin'  
    end 

    def new_user 
    #All of the good stuff - can use params, flash, etc 
    render :action => 'new_user' 
    end 

end 
0

Si dos controladores están tratando de hacer lo mismo, hay una muy buena posibilidad de que esto debería ser en un modelo.Tomar un buen vistazo a su diseño y - lo siento no sé su nivel de experiencia con MVC - leer sobre técnicas controlador delgadas:

http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model http://www.robbyonrails.com/articles/2007/06/19/put-your-controllers-on-a-diet-already http://andrzejonsoftware.blogspot.com/2008/07/mvc-how-to-write-controllers.html

Si el problema es que necesita el otro controlador para hacer el render, entonces tal vez la ruta debería haber señalado allí para empezar, y todavía la técnica de control flaco debe salvar el día.

-1

hacer esto:

class OldController < ApplicationController 
    def old_controller_action 
    if should_use_new_controller 
     new_controller_action 
    end 
    # rest of old and busted 
    end 
end 

y el nuevo controlador de

class NewController < OldController 
    def new_controller_action 
    # new hotness 
    end 
end 
0

Si extraer el código común entre los controladores en un módulo que no funciona para usted, me gustaría utilizar middleware Rack. No he visto el código que utiliza ActiveRecord dentro de middleware, pero no sé de ninguna razón para que no debería ser posible ya que las personas han utilizado Redis y similares.

lo contrario, creo que su única opción sería la de reiniciar el procesamiento de la solicitud con algo como (ejemplo no probado, pseudo):

env['REQUEST_URI'] = new_controller_uri_with_your_params 
call(env) 

Esto es similar a cómo se implementan las pruebas de integración. Pero no sé si todo, desde call hasta llegar a un controlador es idempotente y seguro para volver a ejecutar esta manera. Puede rastrear a través de la fuente y ver. Pero incluso si está bien ahora, podría romperse en cualquier versión futura de rieles o rack.

El uso de middleware evitaría este, ya que permite interceptar la solicitud antes de que se han ejecutado. Todavía debería poder compartir el código con su aplicación de rieles extrayéndolo en módulos comunes incluidos en ambos lugares.

Honestamente, creo que hacer lo simple de factorizar el código de controlador común es probablemente más limpio, pero es difícil saberlo sin los detalles de su situación, así que pensé que podría seguir sugiriendo esto.

Cuestiones relacionadas