Search code examples
ruby-on-railsrubyactiverecordassociationsscopes

Adding a scope to a has_many through association in Rails


I have a Project and User models joined by a Membership model. I want to retrieve a project's members except one user.

project.members.where.not(id: current_user)

Like this answer, I want to use a scope:

class User < ActiveRecord::Base
  scope :except, ->(user) { where.not(id: user) }
end

But this doesn't work.

p.members.except(User.find(1))
User Load (1.0ms)
  SELECT "users".* FROM "users"
  WHERE "users"."id" = $1 LIMIT 1  [["id", 1]]

User Load (0.4ms)
  SELECT "users".* FROM "users"
  INNER JOIN "memberships" ON "users"."id" = "memberships"."user_id"
  WHERE "memberships"."project_id" = $1  [["project_id", 2]]

As you can see this results in two queries, not one. And returns all the members, not taking into account the exclusion.

Why doesn't this work?


Solution

  • Try renaming the scope to something else, like except_for or all_except. Name except is already used by active_record

    http://api.rubyonrails.org/classes/ActiveRecord/SpawnMethods.html#method-i-except

    Also you get 2 queries because you are doing User.find(1) which results in the first query.