I'm trying to give access where an association exists using cancan.
It needs to work with both object attributes and accessible_by selection (so I can't use a block, unless someone tells me how I get around the error when I do that).
I've come up with a brutal hack.
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
There are two ways to achieve this:
This is the recommended approach. Use this, unless you have a good reason not to.
The idea here is to combine a
cannot ability, in conjunction with
can :manage, Recording cannot :manage, Recording, lead_id: nil
Note that the order is important here, so that the rule overriding is correct.
By defining the ability with a block, you can form more complicated queries.
A simple implementation would be as follows:
can :manage, Recording do |recording| recording.lead_id.present? end
However, in order to combine this ability with others, you must also specify the SQL conditions when fetching records. This additional SQL controls
load_resource actions, such as
can :manage, Recording, ["lead_id IS NOT NULL"] do |recording| recording.lead_id.present? end
In order to keep this logic DRY, you could also consider defining your permissions in a block such as:
[Recording, Email].each do |model| can :manage, model cannot :manage, model, lead_id: nil end