Weird LEFT OUTER JOIN on Includes eager loading of

2019-07-17 08:29发布

问题:

I'm not sure it is a active record bug or not. Or is there a way to do .includes and disable the LEFT OUTER JOIN strategy explicitly. Here is my cases:

Given the keyword is 'abc' without a 'dot'

Post.where(:name => "abc").includes(:author)

There are two sqls used as normal

Post Load (0.8ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`name` = 'abc'
Author Load (0.4ms)  SELECT `authors`.* FROM `authors` WHERE `authors`.`id` IN (1)

Given the keyword is 'abc.' with a 'dot'

Post.where(:name => "abc.").includes(:author)

The sql is using LEFT OUTER JOIN strategy, that's confusing.

SELECT `posts`.`id` AS t0_r0, `posts`.`name` AS t0_r1, `posts`.`author_id` AS t0_r2, `posts`.`created_at` AS t0_r3, `posts`.`updated_at` AS t0_r4, `authors`.`id` AS t1_r0, `authors`.`created_at` AS t1_r1, `authors`.`updated_at` AS t1_r2 
FROM `posts` LEFT OUTER JOIN `authors` ON `authors`.`id` = `posts`.`author_id` 
WHERE `posts`.`name` = 'abc.'

I know eager loading with includes is realized with LEFT OUTER JOIN strategy when there are conditions on the association, like

Post.includes(:author).where(:authors => {:name => 'zhougn' })

But in my test cases, there is no such a condition. Basically both Multi-SQL strategy and LEFT OUTER JOIN strategy can give me correct result, but when Posts and Authors are stored in different databases, LEFT OUTER JOIN strategy will fail.

回答1:

Yes, this is a bug. Issue #950: ActiveRecord query changing when a dot/period is in condition value. Fixed in Rails 4, it appears, by deprecating the feature that was getting hung up on this (no solution except to do it different and require the programmer to be explicit when they want a left outer join -- as well as which tables are referenced when using string conditions with includes).

My current dirty workaround (in Rails 3) is to encode/decode the dots like this:

.where("posts.name = REPLACE(?, '˙', '.')", somename.gsub(".", "˙"))