brianhempel / active_record_union

UNIONs in ActiveRecord! Adds proper union and union_all methods to ActiveRecord::Relation.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Not binding polymorphic relation

damaon opened this issue · comments

commented

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"

Thanks for the bug report with the examples. You've been credited in the README.

v1.1.1 is live on RubyGems with the fix in #7.

Let me know if you have any more problems.