2

两种型号(Rails 2.3.8):

  • 用户; 用户名和禁用属性;用户 has_one :profile
  • 轮廓; 全名和隐藏属性

我正在尝试创建一个 named_scope 来消除 disabled=1 和 hidden=1 用户配置文件。User 模型通常与 Profile 模型一起使用,因此我尝试预先加载 Profile 模型(:include => :profile)。

我在名为“可见”的用户模型上创建了一个 named_scope:

named_scope :visible, {
  :joins => "INNER JOIN profiles ON users.id=profiles.user_id",
  :conditions => ["users.disabled = ? AND profiles.hidden = ?", false, false]
}

我注意到,当我在查询中使用 named_scope 时,会忽略急切加载指令。

变体 1 - 仅限用户模型:

 # UserController
 @users = User.find(:all)

 # User's Index view
 <% for user in @users %>
  <p><%= user.username %></p>
 <% end %>

 # generates a single query:
 SELECT * FROM `users`

变体 2 - 在视图中使用 Profile 模型;延迟加载配置文件模型

 # UserController
 @users = User.find(:all)

 # User's Index view
 <% for user in @users %>
  <p><%= user.username %></p>
  <p><%= user.profile.full_name %></p>
 <% end %>

 # generates multiple queries:
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1
  SHOW FIELDS FROM `profiles`
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 5) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 6) ORDER BY full_name ASC LIMIT 1

变体 3 - 急切加载配置文件模型

  # UserController
  @users = User.find(:all, :include => :profile)

  #view; no changes

  # two queries
  SELECT * FROM `users` 
  SELECT `profiles`.* FROM `profiles` WHERE (`profiles`.user_id IN (1,2,3,4,5,6)) 

变体 4 - 使用 name_scope,包括预加载指令

  #UserConroller
  @users = User.visible(:include => :profile)

  #view; no changes

  # generates multiple queries
  SELECT `users`.* FROM `users` INNER JOIN profiles ON users.id=profiles.user_id WHERE (users.disabled = 0 AND profiles.hidden = 0) 
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1

变体 4 确实返回了正确数量的记录,但似乎也忽略了急切加载指令。

这是跨模型命名范围的问题吗?也许我没有正确使用它。

Rails 3 能更好地处理这种情况吗?

4

2 回答 2

4

来自railsapi.com

渴望加载关联

[...] 由于一次只加载一个表,因此条件或订单不能引用除主表之外的表。如果是这种情况,Active Record 会退回到之前使用的基于 LEFT OUTER JOIN 的策略。例如

Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])

将产生一个单一的 SQL 查询,其连接方式如下:LEFT OUTER JOIN comments ON comments.post_id = posts.id 和 LEFT OUTER JOIN authors ON authors.id = posts.author_id。

我相信这回答了您的问题……“变体 #4”中没有急切的加载,因为您引用profilesnamed_scope.

于 2010-06-13T22:59:06.473 回答
0

我相信以下内容可能会为您提供所需的内容:

@users = User.visible.scoped(:include => :profile)

这对我有用,但我没有在我的命名范围的定义中加入其他表。

Jim Benton 在他的博客上提供了一种将其添加到 ActiveRecord 的优雅方式:http: //autonomousmachine.com/posts/2009/10/28/add-a-scope-for-easier-eager-loading

于 2011-09-28T02:25:52.477 回答