CanCan 和数据集

发布于 2024-10-07 04:20:48 字数 1144 浏览 4 评论 0原文

我已经为此苦苦挣扎了一段时间,最后我发现 CanCan 似乎不允许您授权记录集合。例如:

ads_controller.rbability.rb

def index
    @ads = Ad.where("ads.published_at >= ?", 30.days.ago).order("ads.published_at DESC")
    authorize! :read, @ads
end

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

......它工作正常。

任何解释这一点的帮助将不胜感激。

提前致谢。

附:我最初在尝试解决这个问题时遇到了重定向循环。事实证明,有一个问题,其中包含推荐的rescue_from,您将其放入应用程序控制器中以提供不错的错误消息。如果你的root_path设置为你授权的地方!调用不正确(或失败),您将得到一个重定向循环。注释掉rescue_from 通过艰难的方式了解到这一点。

I've been struggling through this for some time and I've finally got to the point where it seems that CanCan doesn't allow you to authorize a collection of records. For example:

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

This results the unauthorised access message when trying to access the index action.

You are not authorized to access this page.

However, if you change the authorize call in the index action to check on the Ad class rather than the collection like so

def index
    @ads = Ad.where("ads.published_at >= ?", 30.days.ago)
    authorize! :read, Ad
end

... it works fine.

Any help in explaining this one would be greatly appreciated.

Thanks in advance.

ps. I was originally getting redirect loops when trying to work this out. It turns out there's a gotchya with the recommended rescue_from that you put in the application controller to give you nice error messages. If your root_path is set to the same place where your authorize! call is not true (or failing), you'll get a redirect loop. Comment out the rescue_from Learnt that one the hard way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

于我来说 2024-10-14 04:20:48

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

CanCan is not designed to be used like that. You can check whether a user has permissions on the model class (e.g. Ad) or a single instance (e.g. @ad).

I suggest you just use accessible_by to filter your collection:

@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

Another approach would be to define a custom permission based on the conditions you use to retrieve the collection:

# 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
夜血缘 2024-10-14 04:20:48

我使用 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-powered-for-collections-of-records-using-cancan.html

I solved this problem usings splats. In this code example, I am trying to authorize users on a collection of TimeOffRequests. They should be authorized if the User is an admin, a manager or the time off request belongs to them.

# 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

I wrote about it in detail here if you're interested: http://zacstewart.com/2012/01/08/defining-abilities-for-collections-of-records-using-cancan.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文