【问题标题】:rails named_scope ignores eager loadingrails named_scope 忽略急切加载
【发布时间】:2010-06-13 22:27:44
【问题描述】:

两种模型(Rails 2.3.8):

  • 用户;用户名和禁用属性;用户 has_one :profile
  • 简介;全名和隐藏属性

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

我在 User 模型上创建了一个名为 'visible' 的 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 模型;延迟加载 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 能更好地处理这种情况吗?

【问题讨论】:

    标签: ruby-on-rails named-scope eager-loading


    【解决方案1】:

    来自railsapi.com

    渴望加载关联

    [...] 因为只加载了一张表 一次,条件或命令 不能引用除 主要的。如果是这种情况 主动 记录回退到以前 使用基于 LEFT OUTER JOIN 的策略。 例如

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

    将产生一个 SQL 查询 沿线连接: LEFT OUTER 在 cmets.post_id 上加入 cmets = posts.id 和 LEFT OUTER JOIN 作者 ON authors.id = posts.author_id。

    我相信这回答了您的问题...“变体 #4”中没有急切加载,因为您在 named_scope 上引用了 profiles 表。

    【讨论】:

    • 好的。我可以将 hidden 属性移动到 User 模型中来完全避免这种情况,但我最好为这种情况找到另一种方法。你能想到一个吗?
    • 您可以创建另一个关联:User has_one :visible_profile。然后你调用@user.visible(:include => :visible_profile),当visible 是named_scope 时只有这个条件:["disabled = ?", false]。就像railsapi.com上的例子一样。
    • @j:我向用户模型添加了一个关联 - has_one :visible_profile, :class_name => 'Profile', :conditions => ["profiles.hidden=?",false]。更改了用户模型的 named_scope - named_scope :visible, { :conditions => ["disabled = ?", false] } 更改了 UserController 的索引操作 - @users = User.visible(:all, :include => :visible_profile)。重新启动服务器。延迟加载仍在发生。配置文件模型过滤器被忽略。想法?
    • 完全不知道。这是来自 railsapi.com 的相同示例:/
    【解决方案2】:

    我相信以下内容可能会满足您的需求:

    @users = User.visible.scoped(:include =&gt; :profile)

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      • 1970-01-01
      相关资源
      最近更新 更多