gpt4 book ai didi

ruby-on-rails - 为什么 Rails 中带有 source_type 的多态关联会导致错误的 SQL 语句?

转载 作者:行者123 更新时间:2023-12-04 06:03:41 29 4
gpt4 key购买 nike

我有三个模型:用户、组织和角色。一个用户通过一个角色可以访问多个组织,一个组织可以通过其角色拥有多个用户。另外,用户可以通过角色访问其他模型,所以角色模型有一个名为“access_to”的多态belongs_to关联,角色表有字段“user_id”、“access_to_id”和“access_to_type”来跟踪关联。这一切都很好,我可以使用 organization.users 和 user.organisations 集合并取回预期的记录。

然而,已经决定将组织模型重命名为“组织”,使用美国英语拼写而不是英国英语(这是一个虚构的例子,真正的问题是相似的,但额外的复杂性与这个问题无关)。该应用程序已运行多年,因此角色表中有数千条记录,其中“access_to_type”设置为“Organisation”(带有“s”)。此外,为了遗留代码的目的,必须保留“组织”模型,而新代码使用“组织”模型。

为了实现这一点,“source_type: 'Organisation'”被添加到 has_many through: associations on User 和新的组织模型,所以完整的代码如下所示:

class Role < ApplicationRecord
belongs_to :user
belongs_to :access_to, polymorphic: true
end

class User < ApplicationRecord
has_many :roles, autosave: true, foreign_key: "user_id"

has_many(
:organizations,
through: :roles,
source: :access_to,
source_type: "Organisation"
)
end

class Organization < ApplicationRecord
self.table_name = 'organisations'

has_many :roles, as: :access_to
has_many :users, through: :roles, source: :access_to, source_type: "Organisation"
end

class Organisation < ApplicationRecord
has_many :roles, as: :access_to
has_many :users, through: :roles
end

调用 "User.first.organizations"仍然按预期工作,并使用此 SQL 语句返回预期的记录:

SELECT "organisations".* FROM "organisations" 
INNER JOIN "roles" ON "organisations"."id" = "roles"."access_to_id"
WHERE "roles"."user_id" = ? AND "roles"."access_to_type" = ?
LIMIT ? [["user_id", 1], ["access_to_type", "Organisation"], ["LIMIT", 11]]

并在用“s”拼写的旧模型上调用“Organisation.first.users”工作正常,生成预期的SQL:

SELECT "users".* FROM "users" INNER JOIN "roles"
ON "users"."id" = "roles"."user_id"
WHERE "roles"."access_to_id" = ?
AND "roles"."access_to_type" = ?
LIMIT ?
[["access_to_id", 1],
["access_to_type", "Organisation"],
["LIMIT", 11]]

但是,调用“Organization.first.users”并没有返回任何记录,查看Rails生成的SQL语句,原因就很明显了:

SELECT "organisations".* FROM "organisations"
INNER JOIN "roles" ON "organisations"."id" = "roles"."access_to_id"
WHERE "roles"."access_to_id" = ?
AND "roles"."access_to_type" = ?
AND "roles"."access_to_type" = ?
LIMIT ?
[["access_to_id", 1],
["access_to_type", "Organization"],
["access_to_type", "Organisation"],
["LIMIT", 11]]

SQL 语句查找角色记录,其中 access_to_type 既是“组织”(带有“z”)又是“组织”(带有“s”)。似乎设置 source_type: "Organisation"在 access_to_type 上添加了一个附加条件,而不是替换 "Organization"拼写为 "z"的默认条件。

它还更改关联以查看“组织”表而不是“用户”表。我希望它简单地改变“access_to_type”条件。

为什么这在一个方向(为用户寻找组织)起作用,而在另一个方向(为组织寻找用户)不起作用?这是 Rails 中的错误(双重条件可能表明),还是我可以在关联配置中修复某些内容以使其正常工作? source_type 怎么能在一个地方搞得这么乱,而在另一个地方工作得很好?

(不幸的是,更改数据库中的 access_to_type 值不是一种选择,因为还有其他代码希望数据保持不变。)

这是在最小的 Rails 6.0 应用程序中重现的问题: https://github.com/RSpace/polymorphic-issue

最佳答案

我找到了一个解决可疑错误的解决方案:有一个未记录的方法,称为 polymorphic_name ActiveRecord 用于确定在进行多态查找时使用的模型名称。
当我将组织模型更改为:

class Organization < ApplicationRecord
self.table_name = 'organisations'

has_many :roles, as: :access_to
has_many :users, through: :roles

def self.polymorphic_name
"Organisation"
end
end
然后 Organization.first.users生成我想要的 SQL:
SELECT "users".* FROM "users" INNER JOIN "roles"
ON "users"."id" = "roles"."user_id"
WHERE "roles"."access_to_id" = ?
AND "roles"."access_to_type" = ?
LIMIT ? [
["access_to_id", 1],
["access_to_type", "Organisation"],
["LIMIT", 11]]
提交修复了我的示例: https://github.com/RSpace/polymorphic-issue/commit/648de2c4afe54a1e1dff767c7b980bb905e50bad
我仍然很想听听为什么另一种方法不起作用。这种解决方法似乎有风险,因为我只是通过挖掘 Rails 代码库发现了这种方法,而且它仅在内部使用: https://github.com/rails/rails/search?q=polymorphic_name&unscoped_q=polymorphic_name
编辑:我现在明白为什么设置 source_type: "Organisation"结果在 organisations 中查找表而不是 users表,如 source_type选项控制模型、表和多态名称 as per the documentation .将“access_to_type”设置两次仍然存在错误,但修复该错误不会使我的用例正常工作,如 source_type首先是控制关联的源类型。我将改为追求获得 polymorphic_name方法记录并因此成为官方 ActiveRecord API 的一部分。

关于ruby-on-rails - 为什么 Rails 中带有 source_type 的多态关联会导致错误的 SQL 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59899559/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com