2012-02-14 10 views
34

Supongamos que tengo un poco de lógica en un controlador de base para pasar información a la vista para construir algo así como una ruta de navegación:¿Filtro para ejecutar antes del renderizado pero después del controlador?

class ContextAwareController < ApplicationController 

    after_filter :build_breadcrumb 

    def build_breadcumb 
    #... 
    end 
end 

Quiero que este método build_breadcrumb para ejecutar después la lógica principal del controlador, pero antes la vista es renderizada

El código anterior se ejecuta demasiado tarde, pero un before_filter sería demasiado temprano.

¿Alguien puede sugerir una forma de lograr esto sin llamar explícitamente a build_breadcumb al final de cada una de las acciones en los controladores secundarios?

Gracias

Respuesta

2

CREO renderizado se inicia cuando hacen que se llama, y ​​no hay manera predeterminada aplazar ella. Aquí hay una cosa que puede hacer:

Los filtros

se aplican en el mismo orden declarado. Por lo tanto, cree un segundo filtro posterior que invoque el procesamiento con un array args almacenado en una variable de clase. Luego, en cualquier lugar que normalmente llamarías render, configura la variable.

49

que tenían el mismo problema y lo resolvió así:

class ApplicationController < ActionController::Base 
    def render *args 
    add_breadcrumbs 
    super 
    end 
end 
+2

Pero esta solución ralentizaría cada renderizado. – freemanoid

+1

Solo ralentizaría los renders hechos desde un controlador en particular. Sería bastante fácil mover esto a un controlador diferente o "sub-controlador" para que solo las acciones que necesitan migas de pan usen esta versión de 'render'. – Jon

+0

También podemos usar una preocupación del controlador para agregar esta funcionalidad selectivamente http://elegantbrew.tumblr.com/post/70990048275/controller-concerns-in-rails-4 – MhdSyrwan

2

También hay algunas gemas para lograr este objetivo. Uno de ellos es rails3_before_render. Funciona de manera similar a los filtros, por ejemplo:

class PostsController < ApplicationController 
    before_render :ping, :except => [:destroy] 

    def index; end 
    def new; end 
    def show; end 
    def destroy; end                   

    private 
    def ping 
     Rails.logger.info "Ping-Pong actions" 
    end 
end 

(código cortó copia de la documentación de la gema)

+3

También vale la pena mencionar que este filtro se ejecuta solo si llame al método _render_, por lo tanto, before_render no se debe usar para actualizar datos en la base de datos cuando existe la posibilidad de redirección. – knarewski

-1

Puede hacer como esto para falsificar un before_render:

class StuffController < ApplicationController 
    before_filter :my_filter, only: [:index, :show] 

    def my_filter 
    @my_filter = true 
    end 
    def _my_filter 
    # Do the actual stuff here 
    end 
    def render(*args) 
    _my_filter if @my_filter 
    super 
    end 
end 

Gracias a @joshua -muheim para la sugerencia sobre el uso de render

2

Si estamos anulando render, en realidad no estamos usando el filtro cadena en absoluto, por lo que podría ser más simple determinar en qué acción estamos utilizando el @_action_name.

StuffController < ApplicationController 

    def my_filter 
    # Do the stuff 
    end 

    def render(*args) 
    my_filter if @_action_name == "show" 
    super 
    end 

end 
Cuestiones relacionadas