我一直在努力解决这个问题,我终于到了CanCan似乎不允许你授权收集记录的地步。例如:
ads_controller.rb
def index
@ads = Ad.where("ads.published_at >= ?", 30.days.ago).order("ads.published_at DESC")
authorize! :read, @ads
end
ability.rb
def initialize(user)
user ||= User.new # Guest user
if user
if user.role? :admin # Logged in as admin
can :manage, :all
else # Logged in as general user
can :read, Ad
can :read_own, Ad, :user_id => user.id
can :create, Ad
end
else # Not logged in (Guest)
can :read, Ad
end
end
这会在尝试访问索引操作时导致未经授权的访问消息。
You are not authorized to access this page.
但是,如果您在索引操作中更改授权调用以检查Ad类而不是像这样的集合
def index
@ads = Ad.where("ads.published_at >= ?", 30.days.ago)
authorize! :read, Ad
end
......工作正常。
非常感谢任何帮助解释这一点。
提前致谢。
PS。在尝试解决这个问题时,我最初获得了重定向循环。事实证明,你在应用程序控制器中提供了一个推荐的rescue_from,它给你提供了很好的错误信息。如果您的root_path设置为您授权的同一个地方!如果调用不正确(或失败),您将获得重定向循环。评论出来救援人员从困难中了解到这一点。
答案 0 :(得分:2)
CanCan的设计并非如此。您可以检查用户是否拥有模型类(例如Ad
)或单个实例(例如@ad
)的权限。
我建议您使用accessible_by
来过滤您的收藏:
@ads = Ad.where("ads.published_at >= ?", 30.days.ago).accessible_by(current_ability)
# @ads will be empty if none are accessible by current user
raise CanCan::AccessDenied if @ads.empty? # handle however you like
另一种方法是根据用于检索集合的条件定义自定义权限:
# ability.rb
can :read_ads_from_past_month, Ad, ["ads.published_at >= ?", 30.days.ago]
# in your controller
def index
authorize! :read_ads_from_past_month, Ad
@ads = Ad.where("ads.published_at >= ?", 30.days.ago)
end
答案 1 :(得分:2)
我使用splats解决了这个问题。在此代码示例中,我尝试在TimeOffRequests
集合上授权用户。如果用户是管理员,经理或休假请求属于他们,则应授权他们。
# time_off_requests_controller.rb
authorize! :read, *@time_off_requests
# Ability.rb
can :manage, TimeOffRequest do |*time_off_requests|
membership.has_any_role?(:admin, :manager) ||
time_off_requests.all? { |tor| membership.id == tor.employee_id }
end
如果您有兴趣,我在这里详细介绍了它:http://zacstewart.com/2012/01/08/defining-abilities-for-collections-of-records-using-cancan.html