2009-09-22 7 views
7

Ich habe eine Reihe von Ressourcen (Reisen, Zeitpläne usw.) mit Aktionen, die nur auf den Besitzer der Ressource beschränkt sein sollten.before_filter: require_owner

Wie implementieren Sie Code mit einer #require_owner-Methode, die in ApplicationController definiert ist, um dies zu erreichen? Im Idealfall sucht der Code die Vererbungskette nach dem Eigentümer, damit der before_filter an einem: comment funktioniert, das zu to_to gehört: trip, das gehört zu: user.

class TripsController < ApplicationController 
    belongs_to :member 
    before_filter :require_owner 

    ... 

end 

Antwort

5

ich nicht ganz der Beschreibung folgen (? Wäre ein Kommentar wirklich von der Reise Eigentümer gehört werden), aber leicht auf jonnii Antwort erweitert, hier ist ein Beispiel, das die Reise Controller beschränkt:

class ApplicationController < ActionController::Base 
    ... 
protected 
    # relies on the presence of an instance variable named after the controller 
    def require_owner 
    object = instance_variable_get("@#{self.controller_name.singularize}") 
    unless current_user && object.is_owned_by?(current_user) 
     resond_to do |format| 
     format.html { render :text => "Not Allowed", :status => :forbidden } 
     end 
    end 
    end 
end 

class TripsController < ApplicationController 
    before_filter :login_required # using restful_authentication, for example 
    # only require these filters for actions that act on single resources 
    before_filter :get_trip, :only => [:show, :edit, :update, :destroy] 
    before_filter :require_owner, :only => [:show, :edit, :update, :destroy] 
    ... 
protected 
    def get_trip 
    @trip = Trip.find(params[:id]) 
    end 
end 

das Modell unter der Annahme, sieht wie folgt aus:

class Trip < ActiveRecord::Base 
    belongs_to :owner, :class_name => 'User' 
    ... 
    def is_owned_by?(agent) 
     self.owner == agent 
     # or, if you can safely assume the agent is always a User, you can 
     # avoid the additional user query: 
     # self.owner_id == agent.id 
    end 
end 

die login_required Verfahren (zur Verfügung gestellt von oder auf einem auth Plugin wie restful_authentication verlassen oder authlogic) stellt sicher, dass der Benutzer angemeldet ist und bietet dem Benutzer eine current_user method, get_trip setzt die Trip-Instanzvariable, die dann in require_owner überprüft wird.

Das gleiche Muster kann an nahezu jede andere Ressource angepasst werden, sofern das Modell die is_owned_by?-Methode implementiert hat. Wenn Sie versuchen, es zu überprüfen, wenn die Ressource ist ein Kommentar, dann würden Sie im CommentsController sein:

class CommentsController < ApplicationController 
    before_filter :login_required # using restful_authentication, for example 
    before_filter :get_comment, :only => [:show, :edit, :update, :destroy] 
    before_filter :require_owner, :only => [:show, :edit, :update, :destroy] 

    ... 
protected 
    def get_comment 
    @comment = Comment.find(params[:id]) 
    end 
end 

mit einem Comment Modell, das wie folgt aussieht:

class Comment < ActiveRecord::Base 
    belongs_to :trip 

    # either 
    # delegate :is_owned_by?, :to => :trip 
    # or the long way: 
    def is_owned_by?(agent) 
    self.trip.is_owned_by?(agent) 
    end 
end 

Stellen Sie sicher, das überprüfen Protokolle, wie Sie dies tun, da assoziationsabhängige Prüfungen in viele Abfragen aufsteigen können, wenn Sie nicht vorsichtig sind.

+0

Dies ist eine großartige Ergänzung, definitiv viel darüber nachdenken zwischen diesem und acl9. – jonnii

+0

Große Antwort. Ich habe diese Lösung und die folgenden Empfehlungen ausprobiert. Beendet mit acl9. Ich wünschte, ich könnte zwei richtige Antworten für diese Frage auswählen ... – Gavin

2

Es gibt ein paar verschiedene Möglichkeiten, dies zu tun. Sie sollten unbedingt das acl9-Plugin (http://wiki.github.com/be9/acl9/tutorial-securing-a-controller) ausprobieren.

Wenn Sie sich entscheiden, dies selbst zu tun, würde ich vorschlagen, so etwas wie tun:

class Trip < ... 
    def owned_by?(user) 
     self.user == user 
    end 
end 

class Comment < ... 
    delegate :owned_by?, :to => :trip 
end 

# in your comment controller, for example 
before_filter :find_comment 
before_filter :require_owner 
def require_owner 
    redirect_unless_owner_of(@commemt) 
end 

# in your application controller 
def redirect_unless_owner_of(model) 
    redirect_to root_url unless model.owned_by?(current_user) 
end 

Verzeihen Sie mir, wenn es irgendwelche Syntaxfehler =) Ich hoffe, das hilft!

+0

Wäre es nicht ein after_filter sein müssen als @comment wird noch nicht festgelegt werden? – dangerousdave

+0

Negative Filter werden in der Reihenfolge ausgeführt, in der sie definiert sind. In diesem Fall wird der Kommentar festgelegt und die Berechtigungen werden überprüft. Diese Art von Zeug ist besser mit etwas wie Cancan oder acl9, tbh getan. – jonnii

+0

Außerdem glaube ich nicht, dass ich jemals ein After_filter verwendet habe. – jonnii

0

Acl9 ist ein Autorisierungs-Plugin. Ich würde Ihnen den Link geben, aber ich habe nicht auf meinem iPhone geschnitten und eingefügt. Wenn niemand sonst den Link zur Verfügung stellt, bis ich an einen Computer komme, werde ich ihn für dich holen. Oder du kannst googeln. Was auch immer. :)

Ich habe gerade erst angefangen, es zu benutzen, aber es hat eine extrem einfache Schnittstelle. Sie müssen nur eine Rollentabelle und eine roles_user erstellen. Lassen Sie mich wissen, wie es läuft, wenn Sie sich entscheiden, es zu benutzen.

0

Oder benutzen Sie einfach vererbten Ressourcen:

InheritedResources auch eine andere Methode begin_of_association_chain genannt einführt. Es wird hauptsächlich verwendet, wenn Sie Ressourcen basierend auf dem @ current_user erstellen möchten und Sie URLs wie "account/projects" haben. In solchen Fällen müssen Sie @ current_user.projects.find oder @ current_user.projects.build in Ihren Aktionen ausführen.

Sie können damit umgehen nur, indem Sie:

class ProjectsController < InheritedResources::Base 
    protected 
    def begin_of_association_chain 
     @current_user 
    end 
end 
+0

Inherited Resources wird von seinem Betreuer nicht mehr empfohlen. – Gavin

Verwandte Themen