Reputation: 464
I have a custom route setup that has a location_id in the url (see below)
resources :menu_items, :path => "/location_menu/:location_id"
So when I hit /location_menu/1
it will show me location_1's menu, /location_menu/2
will show location_2's menu, etc.
Each user is associated to multiple locations (has_many :locations
)
I am trying to use cancan to restrict users from viewing certain menu_item URLS.
For example: User 1 is associated with location 1 and 2. So they can only view the page /location_menu/1
and /location_menu/2
. But they would not be able to view /location_menu/3
.
I created a custom method as a before_filter in my controller:
before_filter :location_check
...
def location_check
@location = Location.find(params[:location_id])
authorize! :see_location, @location
end
In my ability.rb
can :see_location, MenuItem do |location| location && user.location_ids.include?(location.id) end
For some reason, this does not work for me. What could I be doing wrong? If you guys could help me, I would really appreciate it!
Thanks.
Upvotes: 1
Views: 2074
Reputation: 2653
Check once within ability.rb,
user.location_ids.each do |l|
can :view, MenuItem, location_id: l
end
Upvotes: 1
Reputation: 11904
First, I'm not seeing what benefit you get from defining a custom route rather than either a nested resource, but it looks likes its inflating your domain language and resulting in a situation where any particular resource could be referred to by several different names - this will probably become confusing enough that it's worth it to simplify now.
In your location_check
method, you are authorizing see_location
on a Location
instance, but the portion of the Ability
class you've shown us concerns a MenuItem
class. Try defining your ability like this:
can :see_location, Location, id: user.location_ids
Edit
If you need a cancan action to authorize MenuItems
directly, try this (assuming a belongs_to :location
relationship on MenuItem
):
can :view, MenuItem, location_id: user.location_ids
As for your routes, think even simpler. All you need is this:
resources :location_menus
...and then everything related to this goes in a LocationMenusController
. Don't worry that there's no model by the same name - you still can still lookup your locations with Location.find(params[:id])
. From what I understand, everything about the location menu pages hinges around the current user's access to a particular location, so you can treat LocationMenu
as a kind of virtual resource wrapped around Location
.
Upvotes: 0