当 id 不为 nil 时允许访问 cancan / cancancan

Car*_*ela 1 ruby ruby-on-rails cancan

我正在尝试使用 cancan 授予存在关联的访问权限。

它需要同时使用对象属性和 access_by 选择(所以我不能使用块,除非有人告诉我在这样做时如何解决错误)。

我想出了一个残酷的黑客。

lead.rb
has_many :recordings
has_many :emails

ability.rb

can :manage, Lead
can :manage, Recording, :lead_id => (1..Lead.pluck(:id).max).to_a
can :manage, Email, :lead_id => (1..Lead.pluck(:id).max).to_a
Run Code Online (Sandbox Code Playgroud)

我的意思是lead_id不为空...

有什么方法可以做到这一点,而不必每次都创建 100,000 个项目数组?


额外信息:值得注意的是,这些并不是 Recording 和 Emails 模型中唯一可用的控件,因此重要的是我可以添加额外的权限,而不是重置和否定它们。

Tom*_*ord 5

有两种方法可以实现这一点:

1. 能力的组合哈希

这是推荐的方法使用这个,除非你有充分的理由不这样做。

这里的想法是结合一种cannot能力,结合can

can :manage, Recording
cannot :manage, Recording, lead_id: nil
Run Code Online (Sandbox Code Playgroud)

请注意,这里的顺序很重要,因此覆盖规则是正确的。

2. 能力块

通过使用 block 定义能力,您可以形成更复杂的查询。

一个简单的实现如下:

can :manage, Recording do |recording|
  !recording.lead_id.nil?
end
Run Code Online (Sandbox Code Playgroud)

但是,为了将这种能力与其他能力结合起来,您还必须在获取记录时指定 SQL 条件。此附加 SQL 控制load_resource操作,例如index

can :manage, Recording, ["lead_id IS NOT NULL"] do |recording|
  !recording.lead_id.nil?
end
Run Code Online (Sandbox Code Playgroud)

为了保持此逻辑 DRY,您还可以考虑在块中定义您的权限,例如:

[Recording, Email].each do |model|
  can :manage, model
  cannot :manage, model, lead_id: nil
end
Run Code Online (Sandbox Code Playgroud)