Ruby-on-rails Rails 4:如何使用 includes() 和 where() 来检索关联对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18449209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails 4: How to use includes() with where() to retrieve associated objects
提问by emersonthis
I can't figure out how to user the .where()method to retrieve associated model data. In this example, Projects belongs_to Users...
我不知道如何使用该.where()方法来检索关联的模型数据。在此示例中,项目属于用户...
class Project < ActiveRecord::Base
belongs_to :user
has_many :videos
end
class User < ActiveRecord::Base
has_many :projects
end
class ProjectsController < ApplicationController
def invite
@project = Project.includes([:user]).where( {:hashed_id=>params[:id]} ).first
end
end
In App/views/projects/invite.html.erg <%= debug( @project ) %>returns:
在 App/views/projects/invite.html.erg<%= debug( @project ) %>返回:
--- !ruby/object:Project
attributes:
id: 22
name: Some Project Name
belongs_to: 1
instructions: Bla bla bla
active: true
max_duration: 2
max_videos:
created_at: 2013-08-26 15:56:50.000000000 Z
updated_at: 2013-08-26 15:56:50.000000000 Z
hashed_id: '1377532589'
Shouldn't the associated User hash/array be included in this? I know I could manually add it by calling a second find/where( @project.user = User.where( {:id=>@project.belongs_to}) but this doesn't feel like "The Rails Way". What is?
关联的 User 哈希/数组不应该包含在其中吗?我知道我可以通过调用第二个find/ where( @project.user = User.where( {:id=>@project.belongs_to})来手动添加它,但这感觉不像“Rails 方式”。什么是?
SolutionMy initial question was formulated under the incorrect assumption that debug()would return associated objects (this works in cakePHP because it bundles everything into arrays).
解决方案我最初的问题是在不正确的假设下制定的,该假设debug()将返回关联的对象(这在 cakePHP 中有效,因为它将所有内容捆绑到数组中)。
So my original code shouldwork. However, I had incorrectly named the foreign key filed in the table. I got confused by looking at the migration method t.belongs_to(which automatically creates the correctly named foreign_key field, nota field named "belongs_to"). So I also had to rename that column to user_idand now it works just as described in @Veraticus's answer below.
所以我的原始代码应该可以工作。但是,我错误地命名了表中归档的外键。我在查看迁移方法时感到困惑t.belongs_to(它会自动创建正确命名的外键字段,而不是名为“belongs_to”的字段)。因此,我还必须将该列重命名为user_id,现在它的工作方式与下面@Veraticus 的回答中描述的一样。
回答by Veraticus
The userobject is not part of the projectobject, so you won't be able to view it on the project: rather, by saying Project.includes(:user), you're telling Rails to eager-load the referenced association when it finds the project. This saves you a database call down the road. For example, non-eagerly:
该user对象不是对象的一部分project,因此您将无法在项目中查看它:相反,通过说Project.includes(:user),您是在告诉 Rails 在找到项目时预先加载引用的关联。这为您节省了数据库调用。例如,非急切地:
@project = Project.where(id: params[:id]).first # one database call, fetching the project
@project.user # another database call, fetching the user
And eagerly:
并且热切地:
@project = Project.includes(:user).where(id: params[:id]).first # one database call, fetching both project and user
@project.user # no database interaction
This matters more with has_manyqueries where eager-loading associations can save N+1 database queries.
这has_many对于急加载关联可以节省 N+1 数据库查询的查询更重要。
You can verify this is working appropriately by calling @project.userat some point after the eager load and checking your logs: you should see that there was no database call at that point.
您可以通过@project.user在急切加载后的某个时刻调用并检查您的日志来验证这是否正常工作:您应该看到此时没有数据库调用。
回答by przbadu
Eager loading, N+1 query optimization is really an efficient way of loading associations in a single call.
急切加载,N+1 查询优化确实是一种在单个调用中加载关联的有效方式。
- includes() with where() and find()
- include() 与 where() 和 find()
@project = Project.includes(:user).where(hashed_id: params[:id]).first
@project = Project.where(hashed_id: params[:id]).includes(:user).first
* In some cases, It can be useful*
*在某些情况下,它可能很有用*
@projects = Project.find(:all, :includes => :user)
@projects = Project.find(:all, :include => [{:association1 => [:associationA, :associationB, ....]}]

