2

2 つのモデル (Rails 2.3.8):

  • ユーザー; ユーザー名と無効なプロパティ; ユーザー has_one :プロファイル
  • プロフィール; full_name と隠しプロパティ

disabled=1 および hidden=1 のユーザー プロファイルを排除する named_scope を作成しようとしています。User モデルは通常、Profile モデルと組み合わせて使用​​されるため、Profile モデル (:include => :profile) をeager-loadしようとします。

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 を使用すると、eager-loading 命令が無視されることに気付きました。

バリエーション 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 - ビューでプロファイル モデルを使用します。遅延ロード プロファイル モデル

 # 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 は正しい数のレコードを返しますが、eager-loading 命令を無視しているようにも見えます。

これはクロスモデルの名前付きスコープの問題ですか? おそらく私はそれを正しく使用していません。

この種の状況は、Rails 3 でより適切に処理されますか?

4

2 に答える 2

4

railsapi.comから:

アソシエーションの一括読み込み

[...] 一度に読み込まれるテーブルは 1 つだけなので、条件または注文はメイン テーブル以外のテーブルを参照できません。この場合、Active Record は以前に使用された LEFT OUTER JOIN ベースの戦略にフォールバックします。例えば

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

次の行に沿った結合を持つ単一の SQL クエリになります。

これであなたの質問に答えられると思います...「バリエーション#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 に答える