2012-02-14 18 views
34

Supponiamo che io ho una certa logica in un controller di base per passare informazioni al fine di costruire qualcosa come un breadcrumb:Filtro da eseguire prima del rendering ma dopo il controller?

class ContextAwareController < ApplicationController 

    after_filter :build_breadcrumb 

    def build_breadcumb 
    #... 
    end 
end 

voglio questo metodo build_breadcrumb per eseguire dopo la logica controller principale, ma prima la vista è resa.

Il codice sopra riportato è troppo tardi, ma un before_filter sarebbe troppo presto.

Qualcuno può suggerire un modo per farlo senza chiamare esplicitamente build_breadcumb alla fine di ciascuna delle azioni nei child controller?

Grazie

risposta

2

Credo di rendering inizia quando il rendering si chiama, e non c'è modo di default di rinviare esso. Ecco una cosa che potresti fare:

i filtri sono applicati nello stesso ordine dichiarato. Quindi crea un secondo filtro successivo che chiama il rendering con un argomento di array archiviato in una variabile di classe. Quindi ovunque tu chiami normalmente render, imposta la variabile.

49

Ho avuto lo stesso problema e risolto in questo modo:

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

Ma questa soluzione rallenterebbe ogni rendering. – freemanoid

+1

Ridurrebbe solo i rendering effettuati da un particolare controller. Sarebbe stato abbastanza semplice spostarlo su un controller diverso o "sub-controller" in modo che solo le azioni che hanno bisogno di breadcrumb utilizzino questa versione di 'render'. – Jon

+0

Possiamo anche usare un Controller Concern per aggiungere selettivamente questa funzionalità http://elegantbrew.tumblr.com/post/70990048275/controller-concerns-in-rails-4 – MhdSyrwan

2

ci sono anche alcune gemme per raggiungere questo obiettivo. Uno di questi è rails3_before_render. Funziona in modo simile ai filtri, per esempio:

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 

(codice tagliò copiato da documentazione gemma)

+3

Vale anche la pena ricordare che questo filtro viene eseguito solo se chiama il metodo _render_, quindi before_render non dovrebbe essere usato per aggiornare i dati nel database quando esiste una possibilità di reindirizzamento. – knarewski

-1

Si può fare come questo per fingere 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 

Grazie a @joshua -muheim per il suggerimento sull'uso di render

2

Se stiamo ignorando render, non stiamo realmente usando il filtro catena, quindi potrebbe essere più semplice determinare quale azione stiamo usando il @_action_name.

StuffController < ApplicationController 

    def my_filter 
    # Do the stuff 
    end 

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

end 
Problemi correlati