Join GitHub today
ActiveRecord query changing when a dot/period is in condition value #950
Imported from Lighthouse. Original ticket at: http://rails.lighthouseapp.com/projects/8994/tickets/6611
I have created a barebones Rails app demonstrating this bug: https://github.com/coreyward/bug-demo
I also have a Question open on StackOverflow about this: http://stackoverflow.com/questions/5199235/activerecord-query-changing-when-a-dot-period-is-in-condition-value
I don't have the skills/knowledge to know A) where this is coming from or B) how to fix it. Any help would be very much appreciated.
This bug occurs when you have a "child" model (one that
So for the following models:
With the following calls:
The items loaded are ordered by the
If you introduce a period into the name, though (e.g. "John.Smith"), the order scope is ignored.
To see this in action...
And then fire up http://localhost:3000/ and see for yourself.
Thanks @tenderlove; we're getting this issue in 3.1 with an autocomplete which fails (with an exception) iff the user enters data that contains a period. The work-around for this is to do
Confirmed on SQLite with https://github.com/coreyward/bug-demo and rails-HEAD after a few changes to make the project 3.1-compatible.
I started down the path of writing a failing unit test but adding new items to the AR fixtures easily causes a bunch of unintended failures. Any advice?
I've also encountered this bug. My version of it was slightly different (in my case, the select query was ignored, not the order query) so I created a different sample application to demonstrate the error. See https://github.com/peterjm/rails-activerecord-bug-demo
I've confirmed the error with both sqlite3 and mysql2.
So as far as i can tell, its this :
Returning both 'people' and 'xx' as valid table names, causing it to then alias the string (having a table found count greater than 1), and burning the previously defined values.
I've been looking in to this. The problem is that there is no way for us to tell the difference between someone referencing a column and string literal without a full blown SQL parser. The problem stems from the fact that we allow users to add arbitrary snippets of SQL. Arbitrary snippets of SQL, in addition to reconciling eager loaded tables within those snippets makes everything fail.
We can't tell if someone is referencing a "table like thing" from a string literal because string literal quoting changes from database to database. As far as I can tell, we have three options:
I'm firmly in favor of option 3, unless someone more clever than I can come up with a solution. Maybe @jonleighton?
Anyway, here is a test case that will fail:
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index cddd2a6..bf4625c 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -52,6 +52,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase Client.destroyed_client_ids.clear end + def test_select_with_dot_in_name + Developer.where(:name => 'aaron.patterson') + .includes(:audit_logs) + .select('developers.id as omg').order('omg').to_a + end + def test_create_from_association_should_respect_default_scope car = Car.create(:name => 'honda') assert_equal 'honda', car.name
Could there be some way to pass down a hint to the Relation that the string contains SQL, or is known not to contain SQL.
I'm just thinking out loud here, but here's a couple possibilities:
referenced this issue
Oct 20, 2011
True, a deprecation warning would catch every intentional use of the 'fallback' strategy, it'd just fire false positives where this issue is concerned. But that's fine ;)
On Friday, 21 October 2011 at 9:42 PM, Jon Leighton wrote:
referenced this issue
Nov 8, 2011
This feels like a disproportionate response to this failure case.
I'd propose leaving include as-is and finding a workaround or tweak to the heuristic to fix this particular issue.
Agreed that we don't want to write a whole sql parser, but the batch vs joined loading strategy heuristic has worked great.
Saying "include" is at a higher level of abstraction -- it's meant to hide the actual strategy. "I want all this stuff loaded, thanks! also, with these conditions and orderings on it, btw"
So, if anything, I think we should stop over-detecting qualified column names in conditions. And add API, like the
As discussed in campfire, we will investigate using
In most cases, it should be possible to automatically build up the references, e.g.
Where the user is using string SQL, they must add their own references for
It's unlikely that I'll do this in time for 3.2, but if someone else wants to pick it up then be my guest...
Reopening for now, then.
added a commit
Jan 16, 2012
I'm not sure I've missed something, but I can't get it to work.
Gig.select("gigs.*, (SELECT 1 FROM gigs LIMIT 1)").includes(:song).limit(1)
SELECT gigs.*, (SELECT 1 FROM gigs LIMIT 1) FROM `gigs` LIMIT 1 SELECT `songs`.* FROM `songs` WHERE `songs`.`id` IN (1)
Does not work (subquery contains a dot)
Gig.select("gigs.*, (SELECT 1 FROM gigs g2 INNER JOIN songs ON songs.id = g2.song_id LIMIT 1)").includes(:song).limit(1)
SELECT `gigs`.`id` AS t0_r0, `gigs`.`song_id` AS t0_r1, `gigs`.`channel_id` AS t0_r2, `gigs`.`time` AS t0_r3, `gigs`.`listed` AS t0_r4, `songs`.`id` AS t1_r0, `songs`.`artist_id` AS t1_r1, `songs`.`title` AS t1_r2, `songs`.`grade` AS t1_r3, `songs`.`length` AS t1_r4, `songs`.`play_count` AS t1_r5, `songs`.`gigs_count` AS t1_r6 FROM `gigs` LEFT OUTER JOIN `songs` ON `songs`.`id` = `gigs`.`song_id` LIMIT 1
Where did the subquery go?
I'm using rails