Mo.
Mo.

Reputation: 42583

RoR: Different user roles for each new created record?

I want to make a record management system. The system will have 4 different user roles: Admin, Viewer, Editor and Reviewer.

While the first two are easy to implement using gems such as cancan and declarative authorization, the other two are not so simple.

Basically each new record is created by an Admin (only an Admin can create new records), and should have its own separate Editor and Reviewer roles. That is, a user can be assigned many different roles on different records but not others, so a user might be assigned Editor roles for Record A and C but not B etc.

Are there any ways of handling such record-specific user roles?

Upvotes: 2

Views: 769

Answers (1)

MDaubs
MDaubs

Reputation: 3004

This can be accomplished without too much effort with the cancan gem and a block condition. A block condition checks for authorization against an instance. Assuming your Record class had an editors method that returns an array of authorized editors the cancan ability for updating a Record might look something like this:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    ...

    can :update, Record do |record|
      record.editors.include?(user)
    end

    ...    

  end
end

See "Block Conditions" on the CanCan wiki: https://github.com/ryanb/cancan/wiki/Defining-Abilities

Update

Storing which users have which access to which records could be done many ways depending on your specific needs. One way might be to create a model like this to store role assignments:

class UserRecordRoles < ActiveRecord::Base
  # Has three fields:  role, user_id, record_id
  attr_accessible :role, :user_id, :record_id
  belongs_to :user_id
  belongs_to :record_id
end

Now create a has_many association in the User and Record models so that all role assignments can be easily queried. An editors method might look like this:

class Record < ActiveRecord::Base

  ...

  has_many :user_record_roles

  def editors
    # This is rather messy and requires lot's of DB calls...
    user_record_roles.where(:role => 'editor').collect {|a| a.user}
    # This would be a single DB call but I'm not sure this would work.  Maybe someone else can chime in?  Would look cleaner with a scope probably.
    User.joins(:user_record_roles).where('user_record_roles.role = ?' => 'editor')
  end

  ...

end

Of course there are many many ways to do this and it varies wildly depending on your needs. The idea is that CanCan can talk to your model when determining authorization which means any logic you can dream up can be represented. Hope this helps!

Upvotes: 3

Related Questions