我正在Rails 4中使用Cancancan构建一个用于角色授权的应用程序。我定义了一种适用于单个记录的能力,但不适用于:索引操作。
我有一个名为"RVSP"的用户角色。RVSP被分配了WorkOrders
,RVSP将从中创建一个Record
。
class WorkOrder < ActiveRecord::Base
has_one :record
belongs_to :rvsp, class_name: "User"
end
class Record < ActiveRecord::Base
belongs_to :work_order
end
我的问题是:我希望RVSP用户能够读取或更新Records
,其中WorkOrder
被分配给该RVSP。以下是迄今为止的能力定义:
can [:read, :update], Record, Record.for_rvsp(user.id) do |record|
work_order = record.work_order
user.id == work_order.rvsp_id
end
Record.for_rvsp
的作用域是这个怪物:
scope :for_rvsp, -> (rvsp_id) { where( work_order: { rvsp: { id: rvsp_id } } ) }
那么:如果Record's
WorkOrder's
rvsp_id
与当前用户的id匹配,我如何定义所有Records
的能力和/或查询?我怀疑这是某种形式的加入,但我是新手,以前从未这样做过。
附言:我想在Record
中添加一个created_by
列,但我已经通过PaperTrail实现了,我正在使用它进行审计跟踪。但就查询难度而言,Record.versions.first.whodunnit
和Record.work_order.rvsp_id
大致相同。谢谢你能提供的任何建议!
附言:我使用Postgres,但如果可以避免的话,我宁愿不做任何特定于数据库的SQL。
我开始研究联接,它似乎起作用了!我用下面的类方法替换了上面的范围:
def self.for_rvsp(rvsp_id)
joins(:work_order).where(work_orders: {rvsp_id: rvsp_id})
end
我还整理了ability.rb:中的能力
can [:read, :update], Record, Record.for_rvsp(user.id) do |record|
user.id == record.work_order.rvsp_id
end
因此,就索引操作而言,似乎需要在两个地方做同样的事情:定义一个获取所需记录的范围,然后定义块中的功能。作用域确保加载所有正确的记录,并且功能块对它们进行授权。看来对我有用!
我知道这太晚了,但你可以遍历CanCanCan中的关联。
can [:read, :update], Record, work_order: { rsvp_id: user.id }