Rails升级包括方法行为更改

时间:2019-01-03 18:47:35

标签: mysql ruby-on-rails ruby-on-rails-5 rails-upgrade

我已经研究了几天,却没有找到关于这种行为改变的很好的解释。 我正在将Rails应用程序从3.2升级到5.2 这是我的Rails 3应用通过测试的代码。

 ps = Project.includes(:rentals).where('rentals.id IN (?)', [1,2,3,4])

这会吐出一个很大的旧的左联接SQL查询。
但是,如果我在Rails 5中执行相同的查询,则会收到mysql错误

ActiveRecord::StatementInvalid (Mysql2::Error: Unknown column 'rentals.id' in 'where clause': SELECT  `projects`.* FROM `projects` WHERE (rentals.id IN (1,2,3,4)) LIMIT 11 /*application:ConHQ*/)
我对include的理解是,除非在where子句中引用了include表,否则应该执行单独的查询,在这种情况下,应该进行左连接。但似乎这里没有发生。在这种情况下,使用eager_load即可:

 ps = Project.eager_load(:rentals).where('rentals.id IN (?)', [1,2,3,4])

但是我认为include应该做同样的事情。
我还注意到,有时包括确实执行与eager_load

相同的查询
@project = Project.find(174)
@project.rentals.eager_load(:equipment_name).where('equipment_names.id IN (?)', [1,2,3,4])
@project.rentals.includes(:equipment_name).where('equipment_names.id IN (?)', [1,2,3,4])

在这种情况下,eager_load和包括两者都执行左联接。我没有找到任何文档来解释为什么在这些情况下包含不同的行为。究竟包括如何选择它执行的查询?

1 个答案:

答案 0 :(得分:3)

includes只是告诉ActiveRecord应该急切加载数据,但是可以按喜好实现。如果要在查询中引用其他模型,则也必须使用references(:rentals)

ActiveRecord API极其强大且用途广泛,但是与Ruby及其库一样,有许多实现目标的方法。在这种情况下,您还可以使用merge合并另一个关系。

rentals = Rental.where(id: [1,2,3,4])
projects = Project.joins(:rentals).merge(rentals) # you can additionally add includes, too, if you want to access the rentals

这还有一个好处,就是您不必关心Rental模型的表名。