squeel
squeel copied to clipboard
Rails 4.2.3 bug
We just discovered a bug after upgrading to Rails 4.2.3 in the following scope:
scope :can_have_dns_records, -> { where { (dns_zone == true) | ((value == nil) & (domain_id.not_in(Subdomain.where(dns_zone: true).uniq.select(:domain_id)))) } }
This results in the following:
[6] sock-development(main)> Subdomain.can_have_dns_records.find(6787)
Subdomain Load (1.0ms) SELECT `subdomains`.* FROM `subdomains` WHERE `subdomains`.`id` = 1 AND (`subdomains`.`dns_zone` = 1 OR (`subdomains`.`value` IS NULL AND `subdomains`.`domain_id` NOT IN (SELECT DISTINCT `subdomains`.`domain_id` FROM `subdomains` WHERE `subdomains`.`dns_zone` = 6787))) LIMIT 1
Whereas it used to (and should) be the following:
[6] sock-development(main)> Subdomain.can_have_dns_records.find(6787)
Subdomain Load (1.0ms) SELECT `subdomains`.* FROM `subdomains` WHERE `subdomains`.`id` = 6787 AND (`subdomains`.`dns_zone` = 1 OR (`subdomains`.`value` IS NULL AND `subdomains`.`domain_id` NOT IN (SELECT DISTINCT `subdomains`.`domain_id` FROM `subdomains` WHERE `subdomains`.`dns_zone` = 6787))) LIMIT 1
Note the part that says subdomains.id = 6787 versus subdomains.id = 1
More details will follow as I investigate what exactly went wrong.
Small update, I haven't been able to investigate more, but what I didn't notice it that it seems to handle the "binding" incorrectly in the sense that not only did it swap the subdomain id value, it actually used the subdomain id for the (boolean) of subdomains.dns_zone and used 1 (dns zone being true) for the subdomains.id in the query.
Railse 4.2.3 has a rather serious regression, see https://github.com/rails/rails/commit/449241cc30545783419bd8f3cbc7b81137316001 . You may want to test your code against the rails 4-2-stable branch and see if the issue is fixed.
I'm encountering a bug that looks rather similar. However, I'm also able to reproduce this specific issue with rails 4.2.2 (and on rails 4-2-stable). The bug goes away when I don't load squeel by removing it (and only it) from my Gemfile. The bug also goes away when I don't do a join. Here's what happens:
> puts User.joins(:messages).where(name: "test", messages: {id: 1}).where(name: "test2").to_sql
SELECT "users".* FROM "users" INNER JOIN "messages" ON "messages"."user_id" = "users"."id" WHERE "users"."name" = 'test' AND "users"."name" = 1 AND "messages"."id" = 'test2'
It's worth noting that specifying the table on the second where fixes the issue:
> puts User.joins(:messages).where(name: "test", messages: {id: 1}).where("users.name" => "test2").to_sql
SELECT "users".* FROM "users" INNER JOIN "messages" ON "messages"."user_id" = "users"."id" WHERE "users"."name" = 'test' AND "users"."name" = 'test2' AND "messages"."id" = 1
Messages is just a has_many for User. That SQL obviously doesn't work because "test2" isn't an integer:
User Load (0.9ms) SELECT "users".* FROM "users" INNER JOIN "messages" ON "messages"."user_id" = "users"."id" WHERE "users"."name" = $1 AND "users"."name" = $2 AND "messages"."id" = $3 [["name", "test"], ["id", 1], ["name", "test2"]]
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: "test2"
This issue was exposed for me with rails 4.2.3 because the more-abstracted code I have in my app (involving cancancan and a scope) created a more complex SQL query in 4.2.2. That complex query wasn't affected by this issue.
This seems quite similar to the issue I have in https://github.com/activerecord-hackery/squeel/issues/369