Rails 4:如何使用includes()和where()来检索关联对象

时间:2013-08-26 17:00:58

标签: ruby-on-rails ruby associations ruby-on-rails-4

我无法弄清楚如何使用.where()方法来检索关联的模型数据。在此示例中,Projects belongs_to Users ...

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

在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'

不应该将相关的用户哈希/数组包含在其中吗?我知道我可以通过拨打第二个find / where@project.user = User.where( {:id=>@project.belongs_to})来手动添加它,但这并不像&#34; Rails Way&#34;。是什么?

解决方案 我的初始问题是在debug()将返回关联对象的错误假设下制定的(这在cakePHP中起作用,因为它将所有内容捆绑到数组中)。

所以我原来的代码应该工作。但是,我错误地将表中的外键命名为。通过查看迁移方法t.belongs_to(自动创建正确命名的foreign_key字段,名为&#34; belongs_to&#34;的字段),我感到困惑。因此,我还必须将该列重命名为user_id,现在它的工作方式与@ Veraticus的答案中所述的相同。

2 个答案:

答案 0 :(得分:37)

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

热切地说:

@project = Project.includes(:user).where(id: params[:id]).first # one database call, fetching both project and user
@project.user # no database interaction

这对于has_many查询更为重要,其中eager-loading关联可以保存N + 1个数据库查询。

您可以在热切加载并检查日志后的某个时刻调用@project.user来验证这是否正常工作:您应该看到此时没有数据库调用。

答案 1 :(得分:6)

渴望加载,N + 1查询优化实际上是在单个调用中加载关联的有效方式。

- includes()with where()和find()

@project = Project.includes(:user).where(hashed_id: params[:id]).first
@project = Project.where(hashed_id: params[:id]).includes(:user).first

*在某些情况下,它可能很有用*

@projects = Project.find(:all, :includes => :user)
@projects = Project.find(:all, :include => [{:association1 => [:associationA, :associationB, ....]}]