rails: incorrect default scope merging for nested associations
I’ve run into a problem with 4.0.1 related to scope merging of nested associations.
Example model hierarchy:
class Window < ActiveRecord::Base
belongs_to :room
scope :glazed, -> { where( has_glass: 1 ) }
scope :having_handles, -> { where( has_handle: 1 ) }
# only glazed windows count by default
default_scope { glazed }
end
class Room < ActiveRecord::Base
belongs_to :house
has_many :windows
scope :having_openable_windows, ->( ) {
# use unscoped to avoid duplicate application of the default scope of Window
joins(:windows).merge( Window.unscoped.having_handles ).group( 'rooms.id' )
}
# only rooms with openable windows count by default
default_scope { having_openable_windows }
end
class House < ActiveRecord::Base
has_many :rooms
has_many :windows, through: :rooms
scope :having_windows, ->( ) {
joins(:windows).group( 'houses.id' )
}
# only houses with [rooms having openable] windows count by default
default_scope { having_windows }
end
When generating queries, here’s how the Window scopes are applied in 4.0.1:
Window.all.to_sql:
SELECT `windows`.*
FROM `windows`
WHERE `windows`.`has_glass` = 1
This is correct, the default scope (which applies glazed scope) gets included in WHERE section.
Room.all.to_sql:
SELECT `rooms`.*
FROM `rooms`
INNER JOIN `windows`
ON `windows`.`room_id` = `rooms`.`id`
AND `windows`.`has_glass` = 1
WHERE `windows`.`has_handle` = 1
GROUP BY rooms.id
This could still be correct. The default scope of Window now gets included in the JOIN section of windows table, and the additional having_handles scope gets included in WHERE.
House.all.to_sql:
SELECT `houses`.*
FROM `houses`
INNER JOIN `rooms`
ON `rooms`.`house_id` = `houses`.`id`
AND `windows`.`has_handle` = 1
INNER JOIN `windows`
ON `windows`.`room_id` = `rooms`.`id`
AND `windows`.`has_glass` = 1
GROUP BY houses.id
This no longer looks correct.
The having_handles scope should be included in either the JOIN section of windows table or the overall WHERE section, but instead it gets included in the JOIN of rooms where it makes no sense and causes an error.
Since this was not a problem before 4.0.1 when any needed association scopes had to be explicitly merged on each level (and the explicit merges worked correctly!), could this be a problem with how the automatic default scope inclusion works in 4.0.1?
About this issue
- Original URL
- State: closed
- Created 11 years ago
- Comments: 15 (3 by maintainers)
It would be great to have this re-opened. Looks like it’s still happening for us on Rails 4.2.5 and 4.2.6.
Quick example:
Then if we try to join to user it applies the where but not the join.
and it returns
I can reproduce the same issue on rails 5.0.0.1
Same on Rails 5.1.2
I’m also having this issue rails 5.0.0