ruby-on-railsrubymongodbmongoidcancancan

How to check if value is in array on CanCanCan hash of conditions


I have three model classes: PatientBoard, Medication and Customer, which relates to each other like the following:

PatientBoard

associations do 
      has_and_belongs_to_many :customers
      has_many :medications
end

Medication

associations do 
      belongs_to :patient_board
end

Customer

associations do 
      has_many :patient_boards
end

Due to the has_and_belongs_to_many relationship, my patient_board object looks like this:

{
  _id: ObjectId("5e160f235eb3607d57f59341"), 
  name: "test",
  customer_ids: [ObjectId("5db1e6f45eb36059a4d98e7f")]
}

Where the ids from all the customers who have access to that patient board will be inside the customer_ids array.

The problem

When trying to set the permissions to the user, I did it like the following for the PatientBoard:

can :manage, PatientBoard do |pb|
    pb.customer_ids.include? user.id
end

It works for the most part. But the create method still wouldn't work, so I had to insert the following line too:

can :create, PatientBoard

Now it works normally, but when I tried to do the same for the Medication it didn't work:

can :manage, Medication do |m|
    m.patient_board.customer_ids.include? user.id
end

It throws this error message:

The accessible_by call cannot be used with a block 'can' definition. The SQL cannot be determined for :index Medication

So I tried doing it like this:

can :manage, Medication, patient_board: { customers: { id: user.id } }

That way the error message isn't shown anymore, but neither are the medications. And when trying to create a new medication it throws that error:

undefined method `matches?' for #PatientBoard:0x007f663c38d0e8 Did you mean? _matches? matcher

Which I think that makes sense, since its trying to compare an String value (user.id) to an array value (customer_ids)

In resume

How can I check if the user.id is in the customer_ids array using the hash of conditions of the CanCanCan?


Solution

  • So, i managed to solve the problem after checking the issue #345 on the CanCan github.

    Apparently, i had to provide an sql query to match the medications, so i did it like this:

    can [:manage], [Medication], ["#{user.id} in ( select customer_ids from patient_board where id = medications.patient_board.id ) )"] do |t|
       t.patient_board.customer_ids.include? user.
    end