Kurt Mueller
Kurt Mueller

Reputation: 3224

Defining a conditional ability on a model with a has_many relationship

First, my associations:

Form has_many :agreements
Agreement belongs_to :student

I'm trying to define an Ability where the current user can :read, Form when one of its agreements belongs to the the current user.

I've attempted to define the ability like so:

Ability.rb:

can :read, Form do |f|
  f.agreements.select { |a| a.student_id == user.id }.nil? == false
end

I've also tried:

can :read, Form, agreements: { student_id:  user.id }

Unfortunately, the first solution allows all students to view all Forms, even if they are not attached to one of the form agreements. The second solution doesn't allow any student to view a Form, even if they are attached to one of the form's agreements.

What am I doing wrong?

Upvotes: 0

Views: 347

Answers (1)

gregates
gregates

Reputation: 6714

This line is no good:

f.agreements.select { |a| a.student_id == user.id }.nil? == false

The reason is that #select will always return an array. If there are no agreements where the student_id matches the user.id, then you'll get an empty array ([]). But #nil? on any array, including an empty array, is always false. So this line always evaluates to true.

The fix is quite simple. Use the rails method #blank? instead of #nil?. That will return true if the object is nil OR if it's empty. And [].empty? returns true.

tldr: Change the above line to

f.agreements.select { |a| a.student_id == user.id }.blank? == false

Upvotes: 1

Related Questions