Cirdes
Cirdes

Reputation: 47

Using CanCan to authorize a resource based on a many to many association

I have two Models, Events and Users that share a many to many association. A user could be a Admin, Manager or a Producer. Only a producer that belongs to a event should be able to read that event. I tried to apply that restriction on the ability model but it's fails and every producer can read all events. What am I doing wrong?

class Event < ActiveRecord::Base
 has_and_belongs_to_many :producers, :class_name => "User", :join_table => "events_producers"
end


class CreateEventUserJoinTable < ActiveRecord::Migration
  def self.up
    create_table :events_producers, :id => false do |t|
      t.integer :event_id
      t.integer :user_id
    end
  end

  def self.down
    drop_table :events_producers
  end
end

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new() # Guest user
    if user.role? :manager
      can :manage, :all
    elsif user.role? :admin
      can :read, Event
      can :update, Event
      can :create, Event
    elsif user.role? :producer
      can :read, Event do |event|
          event.try(:producers).include?(user)
        end
    end
  end
end

Upvotes: 3

Views: 4770

Answers (2)

Skully
Skully

Reputation: 485

Bit old your question but without block-usage you can define the above condition like that:

can :read, Event, :producers => {:user_id => user.id}

In addition with that line, it should not be needed to ask if the user has a producer role.

Upvotes: 7

Sean Coleman
Sean Coleman

Reputation: 1297

The problem is that conditions in an ability block aren't used when its a class-based call, e.g. index actions. See https://github.com/ryanb/cancan/wiki/Defining-Abilities-with-Blocks for clarification.

For index actions, you must define the restrictions outside the block.

Upvotes: 0

Related Questions