active_record_union icon indicating copy to clipboard operation
active_record_union copied to clipboard

`union` ignored if used in a merge

Open geoffharcourt opened this issue 3 years ago • 0 comments

Hi!

There's a very subtle issue I stumbled upon today if a union-ed scope is passed into ActiveRecord::Relation#merge. Any criteria from a union-built scope gets ignored when the relation gets merged into the scope chain.

https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activerecord/lib/active_record/relation/spawn_methods.rb#L31-L39

https://github.com/rails/rails/blob/fe76a95b0d252a2d7c25e69498b720c96b243ea2/activerecord/lib/active_record/relation/merger.rb#L25-L46

I think this would probably be extremely hard to fix without monkey-patching pretty sensitive code in Relation::Merger, so the best advice I can see here would be to advise users to call #to_a on a union scope before passing it in to merge so that it continues to affect the query results.

A contrived example:

class Dog < ApplicationRecord
  has_many :bones
end

class Bone < ApplicationRecord
  belongs_to :dog 
end

unioned_scope = Dog.where(id: [1, 2]).union(Dog.where(id: [4, 5]))

# This will return bones for Dog #3, which isn't part of the unioned scope!
Bone.joins(:dog).merge(unioned_scope)

geoffharcourt avatar Oct 19 '20 15:10 geoffharcourt