Rails Cancan - 如何限制用户访问自定义URL路由

时间:2013-05-06 16:17:48

标签: ruby-on-rails ruby rubygems gem cancan

我有一个自定义路由设置,在网址中有一个location_id(见下文)

resources :menu_items, :path => "/location_menu/:location_id"

因此,当我点击/location_menu/1时会显示location_1的菜单,/location_menu/2会显示location_2的菜单等。

每个用户都与多个位置相关联(has_many :locations

我正在尝试使用cancan来限制用户查看某些menu_item网址。

例如:用户1与位置1和2相关联。因此,他们只能查看页面/location_menu/1/location_menu/2。但是他们无法查看/location_menu/3

我在控制器中创建了一个自定义方法作为before_filter:

before_filter :location_check
 ... 
def location_check
  @location = Location.find(params[:location_id])
  authorize! :see_location, @location
end

在我的 ability.rb

can :see_location, MenuItem do |location| location && user.location_ids.include?(location.id) end

出于某种原因,这对我不起作用。我能做错什么?如果你们能帮助我,我真的很感激!

感谢。

2 个答案:

答案 0 :(得分:1)

在ability.rb中检查一次,

user.location_ids.each do |l|
  can :view, MenuItem, location_id: l
end

答案 1 :(得分:0)

首先,我没有看到定义自定义路由而不是嵌套资源会带来什么好处,但看起来它会夸大您的域语言并导致某些特定资源可能被多个引用不同的名字 - 这可能会变得令人困惑,现在值得简化。

location_check方法中,您在see_location个实例上授权Location,但您向我们展示的Ability类的部分涉及{{1} } .class。尝试定义你的能力:

MenuItem

修改

如果您需要cancan操作直接授权can :see_location, Location, id: user.location_ids ,请尝试此操作(假设MenuItems上的belongs_to :location关系):

MenuItem

至于你的路线,想想更简单。所有你需要的是:

can :view, MenuItem, location_id: user.location_ids

...然后与此相关的所有内容都在resources :location_menus 中。不要担心没有相同名称的模型 - 您仍然可以使用LocationMenusController查找您的位置。根据我的理解,位置菜单页面的所有内容都取决于当前用户对特定位置的访问权限,因此您可以将Location.find(params[:id])视为一种围绕LocationMenu的虚拟资源。