2

最后更新时间:2013 年 8 月 29 日 18:54 EST

我定义了以下模块,然后将其包含到我的模型中。我正在使用 rolify gem 给我的用户角色。

module Permissions::Offer
  extend ActiveSupport::Concern

  included do
    # `user` is a context of security
    protect do |user, offer|
      # Admins can retrieve anything
      if user.has_role? :administrator
        scope { all }

        # ... and view, create, update, or destroy anything
        can :view
        can :create
        can :update
        can :destroy
      elsif user.present?
        # Allow to read any field
        can :view
        can :create

        # Checks offered_by_id keeping possible nil in mind
        # Allow sellers to modify/delete their own offers
        if offer.try(:offered_by_id) == user.id
          can :update
          can :destroy
        end
      else
        # Guests can't read the text
        cannot :view
      end
    end
  end
end

我正在经历的是,当我执行以下操作时......

respond_with Offer.restrict!(current_user)

它为每个返回的报价查询角色表。无论如何,在请求报价列表时,它是否不会重复提出此请求?我确信我可以缓存响应以避免数据库命中,但我宁愿它也不命中缓存。

如果我打开一个 Rails 控制台并执行以下操作,我会得到相同的结果:

current_user = User.first

Offer.restrict!(current_user).to_a

我已经安装了子弹 gem,看看它是否认为它是一个 N+1 查询,但它没有检测到它。我相信,因为每次创建新的报价实例时都会调用包含的内容,所以它会触发此调用以验证权限。再加上 rolify 不会在任何时间长度内缓存其用户角色检查,这使得这不太理想。我想 rolify 这样做是为了允许即时更改角色,而无需处理清除缓存。到目前为止,我能看到解决这个问题的唯一方法是实现我自己的缓存。

4

1 回答 1

2

我用 rolify 打开了一个问题,看看他们是否有兴趣创建一个更永久的解决方案。对于遇到这种情况的其他人,这就是我在此期间所做的。

def has_role?(role)
  roles = Rails.cache.fetch(roles_for: { object_id: self.object_id }, expires_in: 10.seconds, race_condition_ttl: 2.seconds) { self.roles.map(&:name) }
  roles.include?(role)
end

这并不能做真正的方法所做的一切......但它适合我的目的。

这是任何希望在所有方法上实现类似的东西的人的源链接。

https://github.com/EppO/rolify/blob/master/lib/rolify/role.rb

于 2013-08-30T00:43:57.587 回答