Reputation: 151
Users have permission to manage articles for particular combinations of location and category.
For example Dave may be allowed to manage HR articles for Paris. Paul may be allowed to manage Business articles for London.
The models and their associations are as follows:
I can say:
has_permission_on :articles, :to => :manage do
if_attribute :location => { :permissions => { :user_id => is {user.id} }, :category => { :permissions => { :user_id => is {user.id} } }
end
When I call permitted_to?(:delete) on an article record (whose category id is 1893 and location id is 2939), the following queries are run:
SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1893 LIMIT 1
SELECT `permissions`.* FROM `permissions` WHERE (`permissions`.category_id = 1893)
SELECT `locations`.* FROM `locations` WHERE `locations`.`id` = 2939 LIMIT 1
SELECT `permissions`.* FROM `permissions` WHERE (`permissions`.location_id = 2939)
What I need to be run is really:
SELECT `permissions`.* FROM `permissions` WHERE (`permissions`.category_id = 1893 AND `permissions`.location_id = 2939)
Is there any way to achieve this?
Update
Ok, so I now have an instance method in the article model:
def permitted_user_ids
Permission.select('user_id').where(:location_id => location_id, :category_id => category_id).map(&:user_id)
end
and my rule is now:
has_permission_on :articles, :to => :manage do
if_attribute :permitted_user_ids => contains { user.id }
end
Now when I call permitted_to?(:delete) (or read/update/create/manage) on an article record whose category id is 1893 and location id is 2939, the following query is run:
SELECT user_id FROM `permissions` WHERE `permissions`.`category_id` = 1893 AND `permissions`.`location_id` = 2939
...which is exactly what I want.
Except, that the with_permissions_to scope is behaving very oddly.
Article.with_permissions_to(:read)
Now generates:
SELECT `articles`.* FROM `articles` WHERE (`articles`.`id` = 9473)
...where 9473 is the ID of the current user!
I am very confused.
Upvotes: 4
Views: 307
Reputation: 2938
This should be a comment, but I'm still at 45 :(
You say permission
belongs to user
, location
and category
.
Thus, the permissions table would have user_id, location_id and category_id columns.
If that is true, then why are you declaring that category belongs_to
permission and location belongs_to
permission? Surely the relation should be has_many
?
You should use has_many
in the model which DOES NOT have the foreign key(category and location), and belongs_to
on the model WHICH DOES (permission).
Forgive me if all this is just a typo you made, and what you really meant was permission belongs_to user and has_many location and category.
Upvotes: 0
Reputation: 22331
You can use subclasses and manage the permissions with cancan. You can have a top class Article and then all the kind of articles can be subclasses, and in the subclasses you use cancan to manage their permissions.
Upvotes: 0