关于 Rails 4 和 Rails 5 关联在连接和 where 子句中用法的区别的解释

问题描述 投票:0回答:1

简介

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

逻辑

用户会有很多公司,但我们只想查看设置为

parent
的公司,或者我们标记为“我们当前关心”的公司。不仅如此,我们只想返回“我们目前关心”的母公司是 master_company 的用户。

User通过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 是否支持这种类型的关联使用条款?

这很令人困惑,我提出这个问题是为了看看是否有人能指出我正确的方向,因为 Active Record 查询接口从 Rails 4 更改为 Rails 5 是导致此错误的原因。

感谢所有参与的人!

ruby-on-rails ruby ruby-on-rails-4 ruby-on-rails-5
1个回答
0
投票

如果问题是“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 was allowing inference for what

: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 中提供相同的行为。

© www.soinside.com 2019 - 2024. All rights reserved.