2009-09-22 21 views
7

Tengo una cantidad de recursos (Trips, Schedules, etc.) con acciones que deberían limitarse solo al propietario del recurso.before_filter: require_owner

¿Cómo se implementa el código con un método #require_owner definido en ApplicationController para lograr esto? Idealmente, el código buscará la cadena de herencia del propietario para que el before_filter funcione en un: comentario que pertenece a: viaje que pertenece a: usuario.

class TripsController < ApplicationController 
    belongs_to :member 
    before_filter :require_owner 

    ... 

end 

Respuesta

5

no sigo plenamente la descripción (? Sería un comentario realmente ser propiedad del dueño del viaje), pero en expansión ligeramente sobre la respuesta de jonnii, aquí es un ejemplo que restringe el controlador viaje:

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 

suponiendo que el modelo se parece a esto:

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 

el método login_required (proporcionados por o depender de un complemento auth como restful_authentication o authlogic) se asegura de que el usuario está conectado y proporciona al usuario una current_user método, get_trip establece la variable de instancia de viaje que luego se marca en require_owner.

Este mismo patrón se puede adaptar a casi cualquier otro recurso, siempre que el modelo haya implementado el método is_owned_by?. Si usted está tratando de comprobar que cuando el recurso es un comentario, entonces sería en el CommentsController:

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 

con un modelo que se parece a Comment:

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 

Asegúrese de comprobar la Registre registros mientras hace esto, ya que las comprobaciones dependientes de la asociación pueden convertirse en muchas consultas si no tiene cuidado.

+0

Esta es una gran adición, definitivamente hay que pensar mucho entre esto y acl9. – jonnii

+0

Gran respuesta. Intenté esta solución y acl9 de las recomendaciones a continuación. Terminó usando acl9. Desearía poder seleccionar dos respuestas correctas para esta pregunta ... – Gavin

2

Hay varias maneras diferentes de hacerlo. Definitivamente debería verificar el plugin acl9 (http://wiki.github.com/be9/acl9/tutorial-securing-a-controller).

Si decide que quiere hacer esto por sí mismo, sugeriría hacer algo como:

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 

Perdóname si hay algún error de sintaxis =) Espero que esto ayude!

+0

¿no habría que ser un after_filter como @comment no se establecerá todavía? – dangerousdave

+0

Negativo, los filtros se ejecutan en el orden en que están definidos, lo que en este caso significa que se establecerá el comentario y se verificarán los permisos. Este tipo de cosas se hace mejor con algo como cancan o acl9, tbh. – jonnii

+0

Además, no creo que alguna vez haya usado un after_filter. – jonnii

0

Acl9 es un plugin de autorización. Te daría el enlace, pero no he cortado y pegado en mi iPhone. Si nadie más proporciona el enlace cuando llegue a una computadora, lo conseguiré. O puedes google. Cualquiera. :)

Acabo de comenzar a usarlo, pero tiene una interfaz extremadamente simple. Solo tiene que crear una tabla de roles y un roles_user. Déjame saber cómo te va si decides usarlo.

0

o simplemente utilizar los recursos heredados:

InheritedResources también introduce otro método llamado begin_of_association_chain. Se usa principalmente cuando se quieren crear recursos basados ​​en @current_user y se tienen URL como "cuenta/proyectos". En tales casos, debe realizar @ current_user.projects.find o @ current_user.projects.build en sus acciones.

Usted puede tratar con él sólo por hacer:

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

Los recursos heredados ya no son recomendados por su responsable. – Gavin

Cuestiones relacionadas