Ruby on Rails在哪里查询关系
我试图使用查询与关系。
在这种情况下,如何使用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
(复数forms)而不是其他任何东西的原因。 换句话说,当调用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 * FROM projects WHERE id IN (11,12,13)
并为每条记录构造ActiveRecord对象Project
。 - 预先填充在步骤1中获取的每个
Reason
ActiveRecord对象的project
关联。
上面的最后一步意味着您可以安全地执行:
reasons.first.project
并且不会启动任何查询来获取第一个原因的项目。 这就是includes
用于解决N + 1查询的原因。 但请注意,SQL中没有JOIN子句 – 它们是单独的SQL。 因此,在使用includes
时无法添加SQL约束。
这就是joins
用武之地。它只是连接表,以便您可以在连接表上添加约束。 但是,它不会预先填充您的关联。 实际上, Reason.joins(:project)
将永远不会实例化Project
ActiveRecord对象。
如果要同时执行joins
和includes
,可以使用名为eager_load
的第三种方法。 您可以在此处阅读有关差异的更多信息。