2009-03-23 13 views
10

Mi piacerebbe creare un metodo before_filter nel mio controller domanda come questa ...Come posso inviare un parametro a un filtro precedente?

def check_role(role_name) 
    unless logged_in_user.has_role? role_name 
    flash[:notice] = 'Access to that area requires additional privileges.' 
    redirect_to :back 
    end 
end 

Tuttavia, non sembra come se prima di filtri possono prendere i parametri.

C'è un modo per parametrizzare questa chiamata, o sto provando a guidare una vite con un martello?

risposta

18

Dovresti poterlo fare con un blocco:

before_filter {|controller| controller.check_role('admin') } 
+0

Da dove viene il valore del "controller" param Get Set? – Ethan

+1

before_filter restituirà l'oggetto controller al blocco. Se non si ha familiarità con il formato di blocco di Ruby, le pipe (ad es. ||) delimitano un parametro che viene passato al blocco. (FYI, puoi nominare il parametro come vuoi, ho chiamato "controller" per essere chiaro su cosa viene passato) –

+0

Funziona. Grazie. – Ethan

3

Non credo che si possano passare i parametri ai filtri. Quindi quello che ho fatto in passato è costituito da metodi statici che passano il parametro al metodo che ha bisogno dei parametri.

così avrei qualcosa di simile:

def check_role(role_name) 
    unless logged_in_user.has_role? role_name 
    flash[:notice] = 'Access to that area requires additional privileges.' 
    redirect_to :back 
    end 
end 

def check_admin_role 
    check_role('admin') 
end 

def check_blah_role 
    check_role('blah') 
end 

Poi nel controller si era appena chiamano

before_filter :check_admin_role 

C'è probabilmente un modo per implementare questo con meta-programmazione, ma io sono ancora abbastanza un n00b e non ho ancora capito quella parte;)

4

È possibile utilizzare un po 'di meta-programmazione. Qualcosa di simile (non testato completamente, solo qualcosa per dare un'idea di come potrebbe andare):

Module RoleWithIt 
    Role.all.each do |role| 
    define_method("check_#{role.name}_role".to_sym) do 
     check_role(role.name) 
    end 
    end 

    def check_role(role_name) 
    return if logged_in_user.has_role?(role_name) 
    flash[:notice] = 'Access to that area requires additional privileges.' 
    redirect_to :back 
    end 
end 

ApplicationController.send :include, RoleWithIt 

averlo caricato quando i tuoi inizializza app, appena messo in un file chiamato role_with_it.rb e metterlo nella tua directory lib.

+2

+1 per il nome del modulo – vrish88

4

sto provando a guidare una vite con un martello ?

Er, forse ;-)

Se sto leggendo correttamente, si ha una situazione in cui le azioni di uno di controllo hanno diversi livelli di accesso, in modo che si desidera rimuovere la duplicazione con la creazione di un unico controllo funzione?

Quindi stai cercando di fare qualcosa del genere?

before_filter :check_role('admin'), :only => [:admin, :debug] 
before_filter :check_role('power'), :only => [:edit, :delete] 

Ma il parametro nella cosa paren non è legale. E comunque, vedo ancora un bel po 'di duplicazione qui!

In generale, con un'area di funzionalità ben vista come i filtri del controller, se non si può fare qualcosa, è probabilmente perché si sta guardando qualcosa nel modo sbagliato. (Ricorda che Rails è orgoglioso di descrivere se stesso come "software supponente"!)

Come sarebbe se tu fossi in grado di conoscere il nome dell'azione nel tuo metodo di filtro?

Poi avremmo

before_filter :check_role 

che è abbastanza DRY.

Potremmo definire i permessi in un hash, forse:

Perms = { :admin => ['admin'], :edit => ['admin', 'power'], etc 

... che sembrano racchiudere gli elementi distinti della duplicazione. Se diventasse complesso, l'intera cosa potrebbe spostarsi in una tabella, anche se probabilmente stai duplicando funzionalità già disponibili in un plug-in.

E avremmo

protected 
def check_role 
    for required_role in Perms[params[:action]] 
    return if logged_in_user.has_role? required_role 
    end 
    flash[:notice] = 'Access to that area requires additional privileges.' 
    redirect_to :back 
end 

o qualcosa di simile. params [: action] funziona sulla mia attuale versione di Rails (2.1.2), sebbene il libro Rails (v2) menzioni un metodo action_name che sembra non restituire per me.

+0

Grazie, anche questa è una buona soluzione. Non sapevo di params [: action]. – Ethan

+0

(a dire il vero, ho dovuto scavare anch'io!) –

0

è una vecchia questione, ma se qualcuno si chiede ancora, un buon asnwer per le rotaie 4 può essere trovato here

Problemi correlati