ruby Rails 7 -访问连接模型生成新查询

jtw3ybtb  于 2023-06-05  发布在  Ruby
关注(0)|答案(1)|浏览(110)

我有一个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]]

我期望它应该从已经加载的集合中获取状态,我错过了什么吗?

watbbzwu

watbbzwu1#

但是一旦我从流水线调用状态,它就会无限制地生成新的查询
是的,这就是joins的工作方式,它没有做更多的事情,所以文档甚至懒得添加更多的信息。如果你想在一个查询中访问状态(实际上它最终会是2个查询),你可以使用includes;
ActiveRecord::QueryMethods#includes;
指定要包含在结果集中的关系。它允许您访问User模型的address属性,而无需触发其他查询。
您的查询将稍微更改为;

Pipeline
  .includes(states: :items)
  .where(items: { name: "Lorem" })
  .find('123')

在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(...)相同,因为idfind的默认参数。

相关问题