Default_scope on a join table
Asked Answered
P

2

7

I've got a model setup like the following:

class User
  has_many :items
  has_many :words, :through => :items
end

class Item
  belongs_to :user
  belongs_to :word

  default_scope where(:active => true)
end

class Words
  has_many :items
end

The problem I'm having is that the default_scope is not being applied to the following association:

 user.words

Instead of this SQL:

SELECT `words`.* FROM `words` INNER JOIN `items` ON `words`.id = `items`.word_id WHERE ((`items`.user_id = 1)) AND ((`items.active = 1))

I get this SQL in the logs:

SELECT `words`.* FROM `words` INNER JOIN `items` ON `words`.id = `items`.word_id WHERE ((`items`.user_id = 1)) 

I figure this is because the default scope works for a regular model and its child association, but not for join tables.

What is the correct Rails way to get a join table scope to work between associations without needing to specify it? Does one exist?

Presidency answered 28/3, 2011 at 18:28 Comment(0)
P
11

Figured out the answer with the help of dfr from #ruby-on-rails.

In the User class, set the has_many relation to be:

 has_many :words, :through => :items, :conditions => { "items.active" => true }

This is because although there is a habtm join association between User and Word, the Item model is not actually loaded when user.words is called. Therefore you have to apply the scope on the association within the User model.

Hope that helped someone.

Presidency answered 28/3, 2011 at 18:50 Comment(0)
B
2

Thanks it is helpful. This ticket (though invalid) has people discussing it as well: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/3610-has_many-through-associations-may-not-respect-default_scope-conditions#ticket-3610-17

Personally, I feel like this ticket is NOT invalid. Default Scope is Default Scope.

Browning answered 29/3, 2011 at 14:32 Comment(1)
I agree. Seems like the join model should be loaded when an association is called. I assume it's not for optimization sake. However, I think the join model is the correct place to put that scope, rather than have it just hang off the has_many method in the User model.Presidency

© 2022 - 2024 — McMap. All rights reserved.