Rails:include不包含(Rails :include doesn't include)

23 IT屋

My models:

class Contact < ActiveRecord::Base
  has_many :addresses
  has_many :emails
  has_many :websites
  accepts_nested_attributes_for :addresses, :emails, :websites
  attr_accessible :prefix, :first_name, :middle_name, :last_name, :suffix,
                  :nickname, :organization, :job_title, :department, :birthday,
                  :emails_attributes
end

class Email < ActiveRecord::Base
  belongs_to :contact
  validates_presence_of :account
  validates_format_of :account, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
  attr_accessible :contact_id, :account, :label
end

If I run the following query, the emails are returned as expected:

c = Contact.find(3)
  Contact Load (3.2ms)  SELECT `contacts`.* FROM `contacts` LIMIT 1
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">

c.emails
  Email Load (4.4ms)  SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` = 3
=> [#<Email id: 3, contact_id: 3, account: "not@real.address", label: "work", created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">]

However, attempting to :include the relationship does not:

c = Contact.find(3, :include => :emails)
  Contact Load (0.5ms)  SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`id` = 3 LIMIT 1
  Email Load (0.8ms)  SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` IN (3)
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">

As you can see, the SQL is being executed, but the emails are not being returned. I intend to return all contacts with each containing email(s), so :joins won't do any good. What am I missing?

解决方案

The emails are there. Did you try c.emails? You will find that the emails will be there without Rails doing an additional DB query.

The thing that :include does is called eager loading, which basically means Rails will try a best effort method of prepopulating your objects with their relations, so that when you actually ask for the relation no additional DB queries are needed.

See the section "Eager loading of associations" here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

You might also want to check out this RailsCast:
http://railscasts.com/episodes/181-include-vs-joins

我的模型:



  class Contact< ActiveRecord :: Base 
has_many:地址
has_many:emails
has_many:websites
accepts_nested_attributes_for:addresses,:emails,:websites
attr_accessible:prefix,:first_name,: middle_name,:last_name,:suffix,
:nickname,:organization,:job_title,:department,:birthday,
:emails_attributes
end

class Email< ActiveRecord :: Base
属性_to:联系人
validates_presence_of:account
validates_format_of:account,:with => /\A([^@\s]+)@((?:[-a-z0-9]+\。)+[az]{2,})\Z/i,:on = > :create
attr_accessible:contact_id,:account,:label
end


如果我运行以下查询,按预期返回电子邮件:



  c = Contact.find(3)
接触负载(3.2ms)选择`contacts。**来自`contacts'LIMIT 1
=> #<联系人ID:3,前缀:nil,名字:" Micah",中间名:nil,姓氏:" Alcorn",后缀:nil,昵称:nil,组织:nil,job_title:nil,部门:nil,生日: nil,created_at:" 2011-07-04 23:50:04",updated_at:" 2011-07-04 23:50:04">

c.emails
电子邮件负载(4.4毫秒)从`emails`那里选择`emails`。* emails.`contact_id` = 3
=> [#<电子邮件ID:3,contact_id:3,帐户:" not@real.address",标签:" work",created_at:" 2011-07-04 23:50:04",updated_at:" 2011-07 -04 23:50:04">]


但是,尝试尝试 :include 关系不存在:



  c = Contact.find(3,:include => ;::emails)
接触负荷(0.5ms)在`contacts`中选择`contacts`.id = 3 LIMIT 1限制
电子邮件负荷(0.8ms)选择`emails` 。*从`emails`中的`emails.`contact_id` IN(3)
=>中。 #<联系人ID:3,前缀:nil,名字:" Micah",中间名:nil,姓氏:" Alcorn",后缀:nil,昵称:nil,组织机构:nil,job_title:nil,部门:nil,生日: nil,created_at:" 2011-07-04 23:50:04",updated_at:" 2011-07-04 23:50:04">如您所见,


正在执行SQL,但未返回电子邮件。我打算返回所有包含电子邮件的联系人,因此:joins 不会有任何好处。我想念什么?


解决方案

电子邮件在那里。您是否尝试过 c.emails ?您会发现电子邮件将在其中,而Rails不会执行其他数据库查询。



:include 所做的事情称为"预先加载",这基本上意味着Rails将尝试一种尽力而为的方法。用对象的关系预先填充对象,这样,当您实际请求该关系时,不需要其他数据库查询。



请参见" 更早地加载关联< / strong>"此处:
http://api.rubyonrails.org /classes/ActiveRecord/Associations/ClassMethods.html



您可能还需要查看以下RailsCast:

http://railscasts.com/episodes/181-include-vs-joins


本文地址:IT屋 » Rails:include不包含