我正在尝试将 where 查询与关系一起使用。
在这种情况下如何使用带有关系的 where 进行查询?
这是模型
User
has_many :projects
has_many :reasons, through: :projects
Project
belongs_to :user
has_many :reasons
Reasons
belongs_to :project
这是不起作用的代码
# GET /reasons
def index
reasons = current_user.reasons
updated_at = params[:updated_at]
# Filter with updated_at for reloading from mobile app
if updated_at.present?
# This one doesn't work!!!!!!!!!!!!
reasons = reasons.includes(:projects).where("updated_at > ?", Time.at(updated_at.to_i))
# Get all non deleted objects when logging in from mobile app
else
reasons = reasons.where(deleted: false)
end
render json: reasons
end
---更新---
感谢@AmitA,这是正确的。
reasons = reasons.joins(:project).where("projects.updated_at > ?", Time.at(updated_at.to_i))
最佳答案
如果要查询项目有某些约束的所有原因,则需要使用joins
而不是includes
:
reasons = reasons.joins(:project).where("projects.updated_at > ?", Time.at(updated_at.to_i))
请注意,当 includes
和 joins
都收到符号时,它们会查找与该精确名称的关联。这就是为什么您实际上不能执行 includes(:projects)
,但必须执行 includes(:project)
或 joins(:project)
。
另请注意,where
指定的连接表的约束必须引用表名称,而不是关联名称。这就是为什么我使用 projects.updated_at
(复数)而不是其他任何东西。换句话说,当调用 where
方法时,您位于“SQL 域”中。
includes
和 joins
之间是有区别的。 includes
运行单独的查询来加载依赖项,然后将它们填充到获取的事件记录对象中。所以:
reasons = Reason.where('id IN (1, 2, 3)').includes(:project)
将执行以下操作:
- 运行查询
SELECT * FROM Reasons WHERE id IN (1,2,3)
,并为每条记录构造 ActiveRecord 对象Reason
。 - 查看获取的每个原因并提取其project_id。假设这些是 11、12、13。然后运行查询
SELECT * FROMprojects WHERE id IN (11,12,13)
并为每条记录构造 ActiveRecord 对象Project
。 - 预填充第 1 步中获取的每个
Reason
ActiveRecord 对象的project
关联。
上面的最后一步意味着您可以安全地执行以下操作:
reasons.first.project
并且不会发起查询来获取第一个原因的项目。这就是为什么使用 includes
来解决 N+1 查询。但是,请注意 SQL 中不会出现 JOIN 子句 - 它们是单独的 SQL。因此,当您使用 includes
时,无法添加 SQL 约束。
这就是joins
的用武之地。它只是连接表,以便您可以在连接的表上添加where
约束。但是,它不会为您预先填充关联。事实上,Reason.joins(:project)
永远不会实例化 Project
ActiveRecord 对象。
如果您想同时执行 joins
和 includes
,您可以使用第三种方法,称为 eager_load
。您可以阅读有关差异的更多信息 here .
关于sql - Ruby on Rails where 关系查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36949647/