在 Rails 中,如何在一个查找器中查询两个 has_many 关联?
Posted
技术标签:
【中文标题】在 Rails 中,如何在一个查找器中查询两个 has_many 关联?【英文标题】:In Rails, how do I query two has_many associations in a single finder? 【发布时间】:2022-01-20 16:13:58 【问题描述】:我使用的是 Rails 4.2。我有以下带有几个 has_many 关联的用户模型
class User < ActiveRecord::Base
…
has_many :roles, through: :roles_users
has_many :addresses, dependent: :destroy, as: :addressable, inverse_of: :addressable
class Role < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :roles_users
class RolesUser < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
alias :user :addressable
我想查找具有特定角色但没有任何地址的所有用户。我认为下面会做到这一点
> users = User.includes(:roles, :addresses).where(:roles => :name => 'User', :addresses => :user_id => nil)
但是当我检查结果时,我仍然得到有地址的结果……
2.7.1 :012 > users.last.addresses.count
…
=> 2
编写查询这两个 has_many 关联的查找器的正确方法是什么?
【问题讨论】:
您可以使用 NOT INUser.where.not(id: User.joins(:addresses, :roles).where(roles: name: 'admin' ).select(:id))
对其进行测试。如果不能,您能否列出您在数据库中拥有的用户、角色、角色用户和地址?还将查询中涉及的每个模型中的关系添加到问题中。
谢谢大佬,帮我解决了。如果您想将该查询作为答案包含在内,我会接受。
【参考方案1】:
检查具有 nil 父 ID 的子记录就像在 Rails 4 中执行此操作的方式一样。但如果这不起作用,您可以使用 NOT IN 子句组合:
User
.where
.not(
id: User
.joins(:addresses, :roles)
.where(roles: name: 'User' )
.select(:id)
)
它基本上是通过用户 ID 过滤掉所有具有关联地址、具有角色且角色名称正是“用户”的用户行。你最终会得到这样的 SQL 查询:
SELECT "users".*
FROM "users"
WHERE "users"."id" NOT IN (
SELECT "users"."id"
FROM "users"
INNER JOIN "roles_users" ON "roles_users"."user_id" = "users"."id"
INNER JOIN "roles" ON "roles"."id" = "roles_users"."role_id"
WHERE "roles"."name" = 'User'
)
【讨论】:
嘿,不想回溯我的评论,但是当我将您的查找方法保存到 var 时,“users”,然后运行“users.find|u| u.addresses.count > 0 ”,它返回一个结果。如果我正在查找没有与特定角色匹配的地址的用户,我希望我的查找不会返回任何内容。 不用担心。您可以在问题评论中添加我要求的信息吗? 谢谢。我添加了模型关系。我没有在数据库中添加单独的值,因为太多了,但是如果仍然需要这些值,让我尝试找出一种方法来提出仅与此示例相关的值。 确认,请忽略。一切都很好。我在 cmets (users.find|u| u.addresses.count > 0) 中的发现没有说明指定的角色。当我在混合中添加它时,结果确实是一致的。以上是关于在 Rails 中,如何在一个查找器中查询两个 has_many 关联?的主要内容,如果未能解决你的问题,请参考以下文章
在 Rails 中,如何编写一个带有“where”的查找器来比较两个日期?