2009-03-23 15 views
10

Ich mag würde eine before_filter Methode in meiner Anwendung Controller so ...Wie kann ich einen Parameter an einen Vorher-Filter senden?

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 

jedoch zu schaffen, sieht es nicht, als ob vor Filter Parameter erfolgen können.

Gibt es eine Möglichkeit, diesen Anruf zu parametrisieren, oder versuche ich, eine Schraube mit einem Hammer zu fahren?

Antwort

18

Sie sollten in der Lage sein, dies mit einem Block zu tun:

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

finden Wo der Wert der „Controller“ param gesetzt werden? – Ethan

+1

before_filter liefert das Controller-Objekt für den Block. Wenn Sie mit dem Blockformat von Ruby nicht vertraut sind, begrenzen die Pipes (d. H. ||) einen Parameter, der an den Block übergeben wird. (FYI, Sie könnten den Parameter nennen, was auch immer Sie hier wollen; ich nannte es "Controller", um klar zu sein, was übertragen wird) –

+0

Es funktioniert. Vielen Dank. – Ethan

3

Ich glaube nicht, dass Sie Parameter an Filter übergeben können. Was ich in der Vergangenheit getan habe, sind also statische Methoden, die den Parameter an die Methode übergeben, die die Parameter benötigt.

So würde ich so etwas wie dieses:

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 

Dann in Ihrem Controller Sie gerade nennen würde

before_filter :check_admin_role 

Es gibt wahrscheinlich eine Möglichkeit, dies zu implementieren mit Meta-Programmierung, aber ich bin immer noch ein n00b und habe diesen Teil noch nicht herausgefunden;)

4

Sie können ein bisschen Meta-Programmierung verwenden. So etwas wie diese (völlig ungetestet, nur etwas geben Ihnen eine Vorstellung davon, wie es gehen könnte):

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 

es haben zu laden, wenn Ihre Anwendung initialisiert, es ist nur setzen in einer Datei namens role_with_it.rb und es ausdrückte in deinem lib-Verzeichnis.

+2

+1 für den Modulnamen – vrish88

4

ich versuche eine Schraube mit einem Hammer zu fahren?

Er, vielleicht ;-)

Wenn ich das richtig bin zu lesen, haben Sie eine Situation, in der Aktionen innerhalb eines Controller unterschiedliche Zugriffsebenen haben, so sollten Sie die Vervielfältigung entfernen, indem eine einzelne Prüfung zu schaffen Funktion?

Sie suchen also etwas wie das?

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

Aber der Parameter in Parens Sache ist nicht legal. Und trotzdem sehe ich hier immer noch ein bisschen Duplikation!

Im Allgemeinen, mit einem Bereich der Funktionalität so gut besucht wie Controller-Filter, wenn Sie etwas nicht tun können, ist es wahrscheinlich, weil Sie etwas auf die falsche Art betrachten. (Denken Sie daran, dass Rails sich stolz als "eigensinnige Software" bezeichnet!)

Wie wäre es, wenn Sie den Aktionsnamen in Ihrer Filtermethode kennen könnten?

Dann würden wir

before_filter :check_role 

haben, die ziemlich DRY ist.

Wir konnten Berechtigungen in einem Hash definieren, vielleicht:

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

... die scheinen die unterschiedlichen Elemente der Vervielfältigung zu verkapseln. Wenn es komplex wird, kann das Ganze in eine Tabelle verschoben werden, obwohl du wahrscheinlich die Funktionalität duplizierst, die bereits in einem Plugin verfügbar ist.

Und wir würden haben

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 

oder etwas ähnliches. params [: action] funktioniert auf meiner aktuellen Rails-Version (2.1.2), obwohl das Rails-Buch (v2) eine action_name-Methode erwähnt, die für mich leer zu sein scheint.

+0

Danke, das ist auch eine gute Lösung. Ich wusste nichts über Params [: Action]. – Ethan

+0

(um ehrlich zu sein, musste ich auch graben!) –

0

es ist eine alte Frage, aber wenn jemand noch fragt, kann eine gute asnwer für Schienen 4 here

Verwandte Themen