【问题标题】:Rails 4: How to use includes() with where() to retrieve associated objectsRails 4:如何使用 include() 和 where() 来检索关联对象
【发布时间】:2013-08-26 17:00:58
【问题描述】:

我不知道如何使用.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 &lt;%= debug( @project ) %&gt; 返回:

--- !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=&gt;@project.belongs_to}) 来手动添加它,但这不像“Rails 方式”。是什么?

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

所以我的原始代码应该工作。但是,我错误地命名了表中的外键。查看迁移方法t.belongs_to(它会自动创建正确命名的foreign_key 字段,不是一个名为“belongs_to”的字段),我感到困惑。所以我还必须将该列重命名为user_id,现在它的工作原理与下面@Veraticus 的回答中描述的一样。

【问题讨论】:

  • 你到底想展示什么?您的意思是要显示@project.user 的调试输出吗?或者您是说您的whereincludes 不起作用?如果您想显示user 关联以进行调试,您是否尝试&lt;%= debug(@project.user) %&gt; 而不执行额外的user.where...
  • 如果您只有一个项目对象包含对我来说没有意义。包括选择几个项目并希望在只需一个查询中加载所有相应的用户时,是有道理的,这是你在做什么吗?或者你如何使用includes,希望你记得
  • 答案不再产生单个查询,但这种方法可以:blog.arkency.com/2013/12/rails4-preloading

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


【解决方案1】:

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 查询更为重要,其中预加载关联可以节省 N+1 个数据库查询。

您可以通过在预先加载后的某个时间点调用@project.user 并检查您的日志来验证它是否正常工作:您应该会看到当时没有数据库调用。

【讨论】:

  • 嗯。所以它正在工作,我只是不知道它,因为我(错误地)期待debug 返回关联。说得通。但是,当我&lt;%= debug( @project.user ) %&gt; I get ---`(什么都没有)。`有什么想法吗?
  • 我猜你的项目可能没有用户。
  • 不太清楚你的意思,但我很确定确实如此。我的模型已定义(见上文),并且我的用户表中有一行。我错过了什么吗?
  • 是的,如果您的项目的user_id 属性为空,则无法将其与该用户关联。您可能想查看Rails guide to association basics 以了解如何正确设置关联。
  • 澄清一下,一个用户记录的 belongs_to 值为 1,我认为这是 Rails 4 的外键约定。对吗?
【解决方案2】:

急切加载,N+1 查询优化确实是在单个调用中加载关联的有效方式。

- includes() 与 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, ....]}]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多