0

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.

yerdua
  • 21
  • 6
  • 3
    Please try this -> `Program.last.users.unscoped`. – Arup Rakshit Aug 25 '15 at 04:27
  • I'm aware I can add other scopes on the end of an association. My question was about getting Program.last.users to return the correct scope so we don't have to tack things onto the end of it every time. – yerdua Aug 25 '15 at 17:38
  • Also, `Program.last.users.unscoped` selects all users, including those without an invitation that links them to the program. – yerdua Aug 25 '15 at 17:39

3 Answers3

0
class Program
  # override association with a method
  def users
    Program.joins(:invitation).joins(:users).where('users.registered = true')....ETC
  end
end
penner
  • 2,707
  • 1
  • 37
  • 48
  • I'm trying this one for now, but because it's not an association, preloading won't work. `Program.includes(:users).last` throws an error – yerdua Aug 25 '15 at 17:45
  • You are going to have to write the SQL yourself. Make the users function return a scope and then tack on the necessary additions. Last is the same as order by limit 1... .order('created_at desc').limit(1) – penner Aug 25 '15 at 17:51
0
@program = Program.last    
@user = @program.users.unscoped.all
Jhon Cortes
  • 446
  • 4
  • 13
  • So, when you are thinking what I said is correct, you can vote my answer. Instead of giving the same as your own answer. – Arup Rakshit Aug 25 '15 at 04:41
0

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)
yerdua
  • 21
  • 6