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