before_filter :require_owner

后端 未结 4 475
Happy的楠姐
Happy的楠姐 2021-01-02 16:28

I have a number of resources (Trips, Schedules, etc) with actions that should be limited to just the resource\'s owner.

How do you implement code with a #require_ow

相关标签:
4条回答
  • 2021-01-02 16:57

    I don't fully follow the description (would a comment really be owned by the trip owner?), but expanding slightly on jonnii's answer, here is an example that restricts the trip controller:

    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
    

    Assuming the model looks like this:

    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
    

    The login_required method (provided by or relying on an auth plugin like restful_authentication or authlogic) makes sure that the user is logged in and provides the user with a current_user method, get_trip sets the trip instance variable which is then checked in require_owner.

    This same pattern can be adapted to just about any other resource, provided the model has implemented the is_owned_by? method. If you are trying to check it when the resource is a comment, then you'd be in the 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
    

    with a Comment model that looks like:

    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
    

    Make sure to check the logs as you are doing this since association-dependent checks can balloon into a lot of queries if you aren't careful.

    0 讨论(0)
  • 2021-01-02 17:06

    There's a few different ways to do this. You should definitely check out the acl9 plugin (https://github.com/be9/acl9/wiki/tutorial:-securing-a-controller).

    If you decide you want to do this yourself, I'd suggest doing something like:

    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   
    

    Forgive me if there are any syntax errors =) I hope this helps!

    0 讨论(0)
  • 2021-01-02 17:11

    Or just use inherited resources:

    InheritedResources also introduces another method called begin_of_association_chain. It’s mostly used when you want to create resources based on the @current_user and you have urls like “account/projects”. In such cases you have to do @current_user.projects.find or @current_user.projects.build in your actions.

    You can deal with it just by doing:

    class ProjectsController < InheritedResources::Base
      protected
        def begin_of_association_chain
          @current_user
        end
    end
    
    0 讨论(0)
  • 2021-01-02 17:19

    Acl9 is a authorization plugin. I'd give you the link, but I don't have cut and paste on my iPhone. If no one else provides the link by the time I get to a computer, I'll get it for you. Or you can google. Whichever. :)

    I have only just started using it, but it has an extremely simple interface. You just have to create a roles table and a roles_user. Let me know how it goes if you decide to use it.

    0 讨论(0)
提交回复
热议问题