ruby-on-railsruby-on-rails-3has-many-throughdefault-scope

How can I override a default scope in a has_many :through association?


Override to a default scope isn't being persisted (in a useful way) in a has_many :through association.

Here's the relevant stuff from the models:

class User
  has_one :invitation
  default_scope where(registered: true)
end

class Invitation
   belongs_to :user, conditions: { registered: [true, false] }
   belongs_to :program
end

class Program
  has_many :invitations
  has_many :users, through: :invitations
end

Finding users through invitations works as expected.

Invitation.joins(:user)

generates this:

SELECT `invitations`.* FROM `invitations` INNER JOIN `users` ON `users`.`id` = `invitations`.`user_id` AND `users`.`registered` IN (1, 0)

Given this, I'd assume that Program.last.users should find all relevant users, whether registered is true or false. Instead, I get this:

SELECT `users`.* FROM `users` INNER JOIN `invitations` ON `users`.`id` = `invitations`.`user_id` WHERE `users`.`registered` = 1 AND `invitations`.`program_id` = 52 AND (`users`.`registered` IN (1, 0))

This is the SQL I expect. How do I create an association that gives me this?

SELECT `users`.* FROM `users` INNER JOIN `invitations` ON `users`.`id` = `invitations`.`user_id` WHERE `users`.`registered` IN (1, 0) AND `invitations`.`program_id` = 52

More context: I'm using rails 3.1.3, and upgrading rails isn't a viable option before this feature needs to go out. Getting rid of default_scope isn't a thing I can do either.


Solution

  • I was able to solve this using a has_and_belongs_to_many association. The conditions set on this association override the default scope on Users.

    class Program
      has_and_belongs_to_many :users,
                              join_table: :invitations,
                              conditions: {registered: [true, false]}
    end
    

    program.users produces this SQL:

    SELECT `users`.* 
    FROM `users`
    INNER JOIN `invitations`
    ON `users`.`id` = `invitations`.`user_id` 
    WHERE `invitations`.`program_id` = 111
    AND `users`.`registered` IN (1, 0)