Rails 3拒绝加载

时间:2011-05-11 23:43:21

标签: ruby-on-rails activerecord lazy-loading eager-loading

我正在使用Rails 3.0.7。

我有一些多对多和一些一对多的关联无法加载。

我的协会是:

Person has_many :friends
Person has_many :locations through=> :location_histories
Location belongs_to :location_hour
Location_hour has_many :locations

在我的控制器中,我有以下内容:

@people = Person.includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))").limit(10).all

然后在我看来,我有:

<% @people.each do |person| %>
  <tr>
    <td><%= link_to person.name, person %></td>
    <td><%= link_to person.friends.collect {|s| [s.full_name]}.join(", "), person.friends.first %></td>
    <td><%= link_to person.locations.current.first.name, person.locations.current.first %></td>
  </tr>
<% end %>

locations.current是一个定义为:

的范围
scope :current, lambda {
  where("location_histories.current = ?", true)
}

这按预期工作,首先生成2个数据库调用:一个用于获取人员ID列表,然后是一个大数据库调用,其中所有内容都已正确连接。问题是,之后有以下几行数据库调用:

SELECT 'friends'.* from 'friends' WHERE ('friends'.person_id = 12345)

因此对于视图中循环的每次迭代。不用说这需要一段时间。

我认为.all会强制加载。任何人都知道这里发生了什么? 这在ActiveRecord上花费超过3秒。太长了。

我非常感谢任何建议。

感谢。

3 个答案:

答案 0 :(得分:1)

行。终于解决了。
我需要调用两个连接和包含。我还必须从连接中删除:locations_current关联。它试图通过

来制造一些混乱
... LEFT OUTER JOIN `locations` ON `location_histories`.current = 1 ...  

当然,这不是一个有效的关联。似乎“当前”条款已被转移到JOINS中。

所以现在我有以下,这是有效的。

@people = Person.joins([[:locations=>:location_hour],:friends]).includes([[:locations=>:location_hour],:friends]).where("(location_histories.current = true) AND (people.name LIKE ? OR friends.first_name LIKE ? OR friends.last_name LIKE ? OR (friends.first_name LIKE ? AND friends.last_name LIKE ?))")

总结:
1)我需要同时使用连接和包含来加载和正确解释.while()条件
2)我需要在条件中保持与条件(即:current_locations)的关联。

如果这对你来说似乎是一个明显的错误,请纠正我。它似乎工作。这将活动记录时间降低到不到1秒。

组合连接和包含是否常见?

谢谢!

答案 1 :(得分:0)

我已经找到问题的一部分(虽然仍有一些意想不到的行为)。 我有几个范围,例如locations.current,如上所述定义。

我已将此逻辑移至关联。所以在我的Person模型中我现在有了

has_many :current_locations, :source => :location, :through => :location_histories, :conditions => ["`location_histories`.current = ?", true]

我打电话给

Person.current_locations.first

而不是

Person.locations.current.first.  

所以现在包含按预期进行了预先加载。

问题在于这搞砸了搜索。出于某种原因,当我包含where子句时,现在一切似乎都挂了。对于我添加到include中的每个表,以及当我包含所有必要的表时,事情首先变得非常慢。没有错误。

我知道这一点:当我在where子句中添加符号时,Rails在查询期间执行外连接(如here所述),这是预期的。但是为什么这会导致整个事情崩溃?

(这里的一个小问题是我需要进行字符串比较。为了获得正确的连接,我调用.where

.where(:table =>{:column=> 'string'})

相当于

table.column = 'string'
SQL中的

但是我需要

table.column LIKE '%string%' 

答案 2 :(得分:0)

奇怪的是,对我来说,我有以下行为:

# fails to eager load tags--it only loads one of the tags for me, instead of all of them.
Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags])

但这成功了

Product.find(:all, :conditions => ["products_tags.tag_id IN (?)", 2], :include => [:tags], :joins => [:tags])

就像内部联接表上的查询以某种方式搞乱了急切的加载。所以你的答案可能是正确的。但这里可能有些奇怪的事情发生。 (这里是Rails 2.3.8)。