Devise + CanCan just prevent other users from editing objects

前端 未结 3 959
遥遥无期
遥遥无期 2021-02-10 15:58

How would you prevent other users from editing a object, say a profile object that does - not - belong to themselves?

Most online examples are complexes with multiple us

相关标签:
3条回答
  • 2021-02-10 16:02

    UPDATE

    Seems like the above code examples where correct. After reading all of the docs of cancan rtfm ;p I found out about the role column you need to add.

    Because of the way I have my profile update action organized it seems CanCan does not work! I solved like below:

      def edit
    
        @profile = Profile.find params[:id]
        what = params[:what]
    
        if can? :update, @profile
          if ["basics", "location", "details", "photos", "interests"].member?(what)
            render :action => "edit_#{what}"
          else
            render :action => "edit_basics"
          end
        else
          raise CanCan::AccessDenied.new("Not authorized!", :update, Profile)
        end
      end
    

    Maybe not the cleanest way but the only way to get it to work. Any suggestions on improvements are welcome, I did have the

      load_and_authorize_resource
    

    Inside profiles controller though! Perhaps a bug

    0 讨论(0)
  • 2021-02-10 16:18

    First question is, have you made your roles for the User?

    app/models/user.rb

    class User < ActiveRecord::Base
      attr_accessible :email, :password, :remember_me
      devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, # regular devise stuff
      before_create :setup_default_role_for_new_users
    
      ROLES = %w[admin default banned]
    
      private
    
      def setup_default_role_for_new_users
        if self.role.blank?
          self.role = "default"
        end
      end
    end
    

    As you can see I have 3 different roles here and when a new user is created they are always default users. Now with CanCan set up, lets say you wanted to have the admin be able to do everything, the default users be able to do everything with their own profiles, banned users cannot do anything and guest users be able to see profiles:

    class Ability
      include CanCan::Ability
      # Remember that CanCan is for a resource, meaning it must have a class(model).
    
      def initialize(user)
        user ||= User.new # guest user (not logged in)
    
        if user.role == "admin"
          can :manage, :all
        elsif user.role == "default"
          can :manage, Profile, :user_id => user.id
        elsif user.role == "banned"
          cannot :manage, :all
        else
          can :read, Profile # guest user
        end
      end
    end
    

    So that's how you let users edit only their own profiles and nobody elses.


    Some other handy notes: Make sure you have a user_id column in your Profile table. Also if you may need to let guess users see profiles like this:

    class ProfileController < ApplicationController
        before_filter :authenticate_user!, :except => :show
        load_and_authorize_resource
    end
    

    They won't be able to use any other action and CanCan still checks authentication on everything else except show.

    Good luck!


    UPDATE: Making :role attribute for Users

    What I did was run a migration that would add the role column to the Devise users table:

    rails generate migration add_role_to_users role:string
    

    And then rake db:migrate. The new migration file should look like this and also check your db/schema.rb file to make sure its apart of the users table correctly. If it isn't then rake db:drop, then rake db:create and then rake db:migrate again.

    class AddRoleToUsers < ActiveRecord::Migration
      def self.up
        add_column :users, :role, :string
      end
    
      def self.down
        remove_column :users, :role
      end
    end
    

    This is how you successfully make the user.role work.

    Note: Make sure you leave the line: can :manage, Profile, :user_id => user.id as is with no changes. It should work after adding the role column to user.

    IMPORTANT! If you use Rails 3, DO NOT MAKE role attr_accessible or everyone can edit their roles! Rails 4 uses Strong Parameters by default and is not affected by this issue as you can choose the allowed parameters.

    0 讨论(0)
  • 2021-02-10 16:21

    Give something like this a try....

    can :update, Profile, :user_id => user.id
    
    0 讨论(0)
提交回复
热议问题