我有一个Rails7项目,其中有表
管道
class Pipeline < ApplicationRecord
has_many :states, inverse_of: :pipeline, dependent: :destroy
end
国家
class State < ApplicationRecord
belongs_to :pipeline, inverse_of: :states
has_many :items, inverse_of: :state
end
项目
class Item < ApplicationRecord
belongs_to :state, inverse_of: :items
end
我编写了一个查询,只限制状态上的特定项
@pipeline = Pipeline.joins(states: :items)
.where(states: { items: { name: "Lorem" } })
.find_by(id: '123')
查询:
Pipeline Load (0.7ms) SELECT "pipelines".* FROM "pipelines" INNER JOIN "states" ON "states"."pipeline_id" = "pipelines"."id" INNER JOIN "items" ON "items"."state_id" = "states"."id" WHERE "items"."name" = $1 AND "pipelines"."id" = $2 LIMIT $3 [["name", "Lotem"], ["id", "123"], ["LIMIT", 1]]
但是一旦我从管道中调用状态,它就会无限制地生成新的查询:
puts @pipeline.states.inspect
State Load (0.4ms) SELECT "states".* FROM "states" WHERE "states"."pipeline_id" = $1 /* loading for inspect */ LIMIT $2 [["pipeline_id", "123"], ["LIMIT", 11]]
我期望它应该从已经加载的集合中获取状态,我错过了什么吗?
1条答案
按热度按时间watbbzwu1#
但是一旦我从流水线调用状态,它就会无限制地生成新的查询
是的,这就是
joins
的工作方式,它没有做更多的事情,所以文档甚至懒得添加更多的信息。如果你想在一个查询中访问状态(实际上它最终会是2个查询),你可以使用includes
;ActiveRecord::QueryMethods#includes;
指定要包含在结果集中的关系。它允许您访问User模型的address属性,而无需触发其他查询。
您的查询将稍微更改为;
在Pipeline示例上调用
states
会产生一个新的查询,这是因为您正在调用该对象上的一个示例方法,根据定义,该方法会产生一个新的查询。Active Record不会知道您引用的是已经在查询中创建的内容,除非另有指定(通过使用自定义select
子句或类似子句)。通知
Pipeline.joins(states: :items).where(items: { name: "Lorem" })
和Pipeline.joins(states: :items).where(states: { items: { name: "Lorem" } })
一样,你不需要在状态下嵌套项。find_by(id: ...)
与find(...)
相同,因为id
是find
的默认参数。