ruby-on-rails 关于Rails4和Rails5在joins和where子句中关联用法的差异的解释

0s0u357o  于 2023-05-08  发布在  Ruby
关注(0)|答案(1)|浏览(107)

概要

我正在将一个13年前的Rails 3应用程序升级到Rails 7应用程序,在Rails 5中使用where子句中的关联时遇到了一些问题。

逻辑

用户会有很多公司,但我们只想看看被设置为parent的公司,或者我们标记为“我们目前关注”的公司。不仅如此,我们还希望只返回“我们当前关心的”母公司是master_company的用户。
用户通过UserCompanies拥有多家公司
UserCompanies有一个名为is_parent_company的字段
公司有一个名为is_master_company的字段

问题源代码

整个事情都围绕着一个关联:

has_many :parent_company, -> {where(user_companies: {is_parent_company: true})}, through: :user_companies, source: :company

它应该表示我们上面讨论过的parent_company,它确实如此。

irb(main):067:0> User.first.parent_company
=> #<ActiveRecord::Associations::CollectionProxy [ #<some valid data> ] >

虽然在框架中使用这种关联和过滤器很有吸引力,但我对快速应用程序和可重用查询感兴趣,因此我需要一个可以构建的查询。这就把我们带到了问题所在:尝试在where子句中使用此关联,例如:

User.joins(:parent_company).where(parent_company: {is_master_company: true})

ActiveRecord正在查找一个名为parent_company的表,并抛出了一个错误:missing FROM-clause entry for table "parent_company",这似乎是合理的:毕竟,我们是在连接它,并试图在where子句中使用它,就像我们在表中一样。

工作源代码

User.joins(user_companies: :company).where(user_companies: {is_parent_company: true, companies: {is_master_company: true}})

也许这就是Rails 3和4最初应该做的事情,原始代码只是解决方案代码。让我烦恼的是,这一直在“工作”,并为Rails 3和4吐出正确的用户,但我在Rails 5中抛出了这个错误。Rails 3和4是否支持在where子句中使用这种类型的关联?
这是相当令人困惑的,我提出这个问题是为了看看是否有人能为我指出从Rails 4到Rails 5的Active Record Query Interface更改的正确方向,这是引发此错误的原因。
感谢所有参与的人!

n3schb8v

n3schb8v1#

如果问题是“v4.x和v5.x之间发生了什么变化”,那么您必须深入研究代码库
https://github.com/rails/rails/blob/4-0-stable/activerecord/lib/active_record/relation/query_methods.rb
https://github.com/rails/rails/blob/5-0-stable/activerecord/lib/active_record/relation/query_methods.rb
但是,您最终将不得不在底层方法中进行微小的更改,并且在完全了解ActiveRecord的核心内部之前,可能仍然得不到明确的答案。这种方法的好处是…您将完全了解ActiveRecord的核心内部结构。
不过,我想你已经触及到了更重要的问题:
我是否可以编写向后兼容的代码,这样我就有信心它会产生相同的结果?
也许这就是Rails 3和4最初应该做的事情,原始代码只是解决方案代码。
是的,看起来Rails < 4允许推断:parent_company的含义,但Rails 5+中的变化表明这是有问题的。
您可以尝试@spickermann的建议,澄清您的关系以符合Rails约定。因为Rails是“约定优于配置”,所以关系中的多元化确实很重要。

class User < ApplicationRecord

  has_many :user_companies
  has_many :companies, through :user_companies

  # a collection is returned, even if it's always a collection of one, so it should be pluralized
  has_many :parent_companies, -> {where(user_companies: {is_parent_company: true})}, through: :user_companies, source: :company
end

在Rails 3、4和5中,仅这一点就有可能提供相同的行为。

相关问题