I have a Rails app, using CanCan for authorization. I have Users that can have Memberships in Groups. I would like to create a CanCan rule that authorizes a user to create a group membership only if they are not already a member of that group. So far I have been unable to figure out the magic:
class Group < ActiveRecord::Base
has_many :memberships
has_many :members, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :member, class_name: 'User'
belongs_to :group
end
class User < ActiveRecord::Base
has_many :groups, through: :memberships
has_many :memberships, foreign_key: 'member_id'
end
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
# One of my sad attempts...
can :create, Membership do |membership|
!membership.group.has_member(user)
end
end
end
<% if can? :create, Membership %>
View code for creating memberships...
<% end %>
Your assistnace is appreciated. Also, I do understand that CanCanCan is the successor of CanCan. A CanCanCan answer will be fine.
CanCan blocks only work on model instances (see this wiki page) and right now your can?
sends the model class, not an instance.
In order for this to work, you need to pass an instance of Membership. You can do something like this (assuming @group is the group the user wants to join)
<% if can? :create, Membership.new(group: @group) %>
View code for creating memberships...
<% end %>
I would recommend, however, that you put the ability on the group. In my opinion, it is a more direct approach.
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
can :join, Group do |group|
!group.members.include?(user)
end
end
end
View
<% if can? :join, @group %>
View code for creating memberships...
<% end %>