This project is archived and is in readonly mode.
Move conditions for polymorphic joins from WHERE to ON clause
Reported by Ryan Aipperspach | April 7th, 2011 @ 11:02 PM
The problem
Polymorphic joins currently add a condition (e.g., taggable_type="Post") to the WHERE clause. When the table being joined is in an outer join (e.g., via a Tag.include(:tagged_posts)), this precludes finding objects that have no matching objects across the join (e.g., Tags that don't have any Posts).
To reproduce, see
test_has_many_polymporphic_with_source_type_and_some_empty_children
in join_model_test.rb
.
In the current code, the query:
Tag.includes(:tagged_posts).where(:taggings => {:id => nil}).limit(100)
generates SQL like:
SELECT ... FROM tags LEFT OUTER JOIN "taggings" ON "taggings"."tag_id" = "tags"."id" LEFT OUTER JOIN "posts" ON "posts"."id" = "taggings"."taggable_id" WHERE "taggings"."taggable_type" = 'Post' AND "taggings"."id" IS NULL LIMIT 100
Which will never find any results because of the conflicting
conditions "taggings"."taggable_type" = 'Post'
and
"taggings"."id" IS NULL
.
After applying this patch, it instead generates:
SELECT ... FROM "tags" LEFT OUTER JOIN "taggings" ON "taggings"."tag_id" = "tags"."id" LEFT OUTER JOIN "posts" ON "posts"."id" = "taggings"."taggable_id" AND "taggings"."taggable_type" = 'Post' WHERE "taggings"."id" IS NULL LIMIT 100
Solution
ThroughReflection#conditions
currently applies a
condition of foreign_type => options[:source_type]
whenever an association provides a source_type (either directly, or
implicitly via a :through
or :source
option, which is the source of the errant condition in the query
above.
This was replaced with a constraint that is inserted when a join
is created, in both AssociationScope#add_constraints
and JoinAssociation#join_to
(with the shared code for
generating the constraint in join_helper.rb
:
def append_source_type_condition(constraint, table, foreign_table, reflection)
source_type = reflection.options[:source_type] ||
(reflection.source_reflection &&
reflection.source_reflection.options[:source_type])
if (source_type)
table.create_and([
constraint,
foreign_table[reflection.foreign_type].eq(source_type)
])
else
constraint
end
end
No comments found
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>