【问题标题】:Rails upgrade includes method behavior changeRails 升级包括方法行为更改
【发布时间】:2019-01-03 18:47:34
【问题描述】:

我已经挖掘了几天,还没有找到一个很好的解释来解释这种行为变化。 我正在将 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*/)

我对包含的理解是它应该执行单独的查询,除非在 where 子句中引用了包含的表,在这种情况下它应该执行左连接。但似乎这并没有发生在这里。在这种情况下使用 eager_load 有效:

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

但我认为包含应该做同样的事情。
我还注意到,有时包含 does 执行与 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 和包括都执行左连接。我还没有找到任何文档来解释为什么包含在这些情况下的行为不同。究竟是如何选择它执行的查询?

【问题讨论】:

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


【解决方案1】:

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 模型的表名。

【讨论】:

  • 很高兴知道!这回答了我问题的第一部分,但我仍然不明白为什么我的两种情况会返回不同的结果。 Project.includes(:rentals).where('rentals.id = 2') 出错,但 @project.rentals.includes(:equipment_names).where('equipment_names.id =2') 执行左连接,没有错误。我想我仍然对为什么这些情况会表现不同感到困惑。
  • 两个关联都是has_many吗?也许一个是habtm?为了确定并学习一些好的 Ruby,我通常建议查看 the source。对我来说,这通常足以回答一个 SO 问题:所以我有理由深入研究 Rails 代码;)
  • 啊哈,你是对的。这是一个belongs_to,我在最初创建问题时误读了。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
相关资源
最近更新 更多