Not binding polymorphic relation
damaon opened this issue · 3 comments
Check out this code:
filtered_questions.to_sql`
=> "SELECT "questions"."id", "questions"."title", "questions"."meta", "questions"."content", "questions"."updated_at", "questions"."user_id", 'Question' AS "type" FROM "questions" INNER JOIN "taggings" ON "taggings"."tagged_id" = "questions"."id" AND "taggings"."tagged_type" = 'Question' INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "questions"."deleted_at" IS NULL AND (1=0)"
filtered_findings.to_sql
=> "SELECT "findings"."id", "findings"."title", "findings"."meta", "findings"."content", "findings"."updated_at", "findings"."user_id", 'Finding' AS "type" FROM "findings" INNER JOIN "taggings" ON "taggings"."tagged_id" = "findings"."id" AND "taggings"."tagged_type" = 'Finding' INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "findings"."deleted_at" IS NULL AND (1=0)"
filtered_questions.union_all(filtered_findings).to_sql
=> "SELECT "questions".* FROM ( (SELECT "questions"."id", "questions"."title", "questions"."meta", "questions"."content", "questions"."updated_at", "questions"."user_id", 'Question' AS "type" FROM "questions" INNER JOIN "taggings" ON "taggings"."tagged_id" = "questions"."id" AND "taggings"."tagged_type" = INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "questions"."deleted_at" IS NULL AND (1=0)) UNION ALL (SELECT "findings"."id", "findings"."title", "findings"."meta", "findings"."content", "findings"."updated_at", "findings"."user_id", 'Finding' AS "type" FROM "findings" INNER JOIN "taggings" ON "taggings"."tagged_id" = "findings"."id" AND "taggings"."tagged_type" = INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "findings"."deleted_at" IS NULL AND (1=0)) ) questions"
AND \"taggings\".\"tagged_type\" = INNER JOIN
<- error spotted?
This gem somehow misses these two bindings and when I try to execute query I get error that 2 bindings are missing.
I'm running into something similar while attempting to update to Rails 4.2.4 (from 4.1.6), and using MySQL. It's not a polymorphic relation, but it looks like a similar parsing error is happening. Here's a really contrived example:
# person.rb
class Person < ActiveRecord::Base
has_many :active_emails, -> { where active: true }, class_name: 'Email'
has_many :twitters
end
Say we want to find all people with active emails starting with "johndoe".
Person.joins(:active_emails).where('address like ?', 'johndoe%')
yields
SELECT `people`.* FROM `people` INNER JOIN `emails` ON `emails`.`person_id` = `people`.`id` AND `emails`.`active` = 1 WHERE (address like 'johndoe%')
So far, so good. Now let's say we want to find all people with either an active email starting with "johndoe" or a Twitter handle starting with "johndoe".
Person.joins(:active_emails).where('address like ?', 'johndoe%').union(Person.joins(:twitters).where('handle like ?', 'johndoe%'))
yields
SELECT `people`.* FROM ( (SELECT `people`.* FROM `people` INNER JOIN `emails` ON `emails`.`person_id` = `people`.`id` AND `emails`.`active` = WHERE (address like 'johndoe%')) UNION (SELECT `people`.* FROM `people` INNER JOIN `twitters` ON `twitters`.`person_id` = `people`.`id` WHERE (handle like 'johndoe%')) ) people
Note that where it used to say, "AND emails
.active
= 1 WHERE...", the "1" has now mysteriously vanished, and this is no longer valid SQL.
This does not happen with sqlite3, presumably because the original syntax is different:
-- sqlite3 sanitizes out the parameter in the scope block
SELECT "people".* FROM "people" INNER JOIN "emails" ON "emails"."person_id" = "people"."id" AND "emails"."active" = ? WHERE (address like 'johndoe%') [["active", "t"]]
I can reproduce on SQLite…
class User < ActiveRecord::Base
has_many :posts
has_many :drafts, -> { where draft: true }, class_name: "Post"
end
class Post < ActiveRecord::Base
belongs_to :user
end
User.joins(:drafts).union(User.where(id: 11)).to_sql
SELECT "users".* FROM (
SELECT "users".*
FROM "users"
INNER JOIN "posts" ON "posts"."user_id" = "users"."id" AND "posts"."draft" = 11
UNION
SELECT "users".* FROM "users"
WHERE "users"."id" =
) "users"