ユーザ用ツール

サイト用ツール


rails:active_record

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
rails:active_record [2010/01/25 08:21] – 作成 - 外部編集 127.0.0.1rails:active_record [2024/01/10 14:30] (現在) nullpon
行 71: 行 71:
  
 ===== nemed_scope ===== ===== nemed_scope =====
-(rails 2.1 or later) 
  
 よくある検索条件をメソッド化できる。 よくある検索条件をメソッド化できる。
 <code rubyt> <code rubyt>
 User < ActiveRecord::Base User < ActiveRecord::Base
-  named_scope :active, :conditions => { "state" => "active" } +  scope :active, where(state: "active") 
-  named_scope :teenager, :conditions => {"age=13..19 } +  scope :teenager, where("age >= 13 and age <= 19") 
-  named_scope :male :condtions => {"sex" => } +  scope :male, where(gender: 1) 
-  named_scope :age, lambda{ |x{ :conditions => ["age = ?", x] }}+  scope :age, -> x { where(age: x}
 end end
 </code> </code>
行 147: 行 146:
  
 検索時は 検索時は
-  LimitedItem.find(:all+  LimitedItem.all 
 とすれば、 とすれば、
   select * from items where type = "LimitedItem";   select * from items where type = "LimitedItem";
行 160: 行 159:
 class ItemsController class ItemsController
   def index   def index
-    @items = Item.find(:all)+    @items = Item.all
   end   end
 end end
行 207: 行 206:
 当然、railsを通さずに直接レコードを追加、削除するとカウンタキャッシュの値が不正になるので注意。 当然、railsを通さずに直接レコードを追加、削除するとカウンタキャッシュの値が不正になるので注意。
  
-===== eager loading で inner join ===== +===== テーブル結合 ===== 
-Rails 2.3.4+ 
 +==== eager_loadとjoin ==== 
 + 
 +eager loading(多対一リレーションなデータで、多を検索したときに一のデータもjoinして取っておく事)する
  
-eager loading(多対一リレーションなデータで、多を検索したときに一のデータもjoinして取っておく事)するには include オプションを使う。 
 <code ruby> <code ruby>
 class Book < ActiveRecord::Base class Book < ActiveRecord::Base
行 216: 行 217:
 end end
  
-left outer join +取得されたbookの数だけauthorを取得するSQLを実行(N+1クエリ問題) 
-books = Book.find( +books = Book 
-           :conditions => ["title LIKE ?", "あ%"], +        .where("title LIKE ?", "あ%")
-           :include => [author])+
  
 books.each { |book| puts book.author.name } books.each { |book| puts book.author.name }
 </code> </code>
-関連テーブルの内容はleft outer joinで取得される。よって author が nil にもなるので注意。 
  
-inner joinでeager loadingしたいときは joins と include 両方指定する+<code sql> 
 +select .. from books where (title like 'あ%'); 
 +select .. from authors where id = 1; -- booksの取得件数だけSQLがauthor取得するSQLが実行されてしまう 
 +select .. from authors where id = 2; 
 +select .. from authors where id = 5; 
 +
 +
 +
 +</code> 
 + 
 <code ruby> <code ruby>
-books = Book.find( +# authorも同時に取得(left outer joinを使用) 
-           :conditions => ["title LIKE ?", "あ%"], +books = Book 
-           :include => [:author], +        .where("books,title LIKE ?", "あ%") 
-           :joins => [:author])+        .eager_load(:author)
  
 books.each { |book| puts book.author.name } books.each { |book| puts book.author.name }
 </code> </code>
-joinsだけ指定すると関連テーブルを inner join するが、関連テーブルの内容は eager loading されない。joinsは関連オブジェクトが存在するレコードだけを取得するためのオプション、includeは関連オブジェクトをeager loadingのためのオプションであって役割が別なのである。 
  
-joinsとincludeオプションを両方指定しときwill_paginateプラグインを使っているとSQLでレコド数カウントするに left outer join と inner join 両方含まれてしまう(結果inner joinの場合と同じ)。これはwill_paginate 2.3修正されてる。+<code sql> 
 +select books.*, authors.* from books  
 +  left outer join authors on books.author_id = authors.id where (books.title like 'あ%'); 
 +</code> 
 + 
 +left outer joinの、 author が nil になる可能性があるので注意。inner joinで結合した場合はjoinsを併用する 
 + 
 +<code ruby> 
 +# authorも同時に取得(inner joinを使用) 
 +books = Book 
 +        .where("books.title LIKE ?", "あ%"
 +        .eager_load(:author) 
 +        .joins(:author) 
 + 
 +books.each { |book| puts book.author.name } 
 +</code> 
 + 
 +<code sql> 
 +select books.*, authors.* from books  
 +  inner join authors on books.author_id = authors.id where (books.title like 'あ%'
 +</code> 
 + 
 + 
 +joinsを単体で使用するとSQL発行時にauthorsテブルinner joinするがauthorデータの取得は行わない。検索条件authorを使いたいがauthorのデータは不要な場合に使用する 
 + 
 +<code ruby> 
 +# 著者名が「あ」で始まる書籍を取得 
 +books = Book 
 +        .where("author.name LIKE ?", "あ%"
 +        .joins(:author) 
 +</code> 
 + 
 +<code sql> 
 +select books.* from books  
 +  inner join authors on books.author_id = authors.id where (author.name like 'あ%'
 +</code> 
 + 
 + 
 +==== preload ==== 
 + 
 +preloadはjoinせず、2つSQLを発行して関連データを取得する。 
 + 
 +<code ruby> 
 +# 著者名が「あ」で始まる書籍を取得 
 +books = Book 
 +        .where("books.title LIKE ?", "あ%"
 +        .preload(:author) 
 + 
 +books.each { |book| puts book.author.name } 
 +</code> 
 + 
 +<code sql> 
 +select books.* from books where (books,title like 'あ%'); 
 +select authors.* from authors where authors.id in (1,2,5,...); -- 最初SQLで取得されたレコードのauthor_idで検索 
 +</code> 
 + 
 + 
 +==== includes ==== 
 + 
 +includesは特殊で、通常はpreloadと同じ動きだが、結合テーブル側を検索条件に含めるとeager_loadに変わる 
 + 
 + 
 +<code ruby> 
 +books = Book 
 +        .where("books,title LIKE ?", "あ%"
 +        .includes(:author) 
 + 
 +books.each { |book| puts book.author.name } 
 +</code> 
 + 
 +<code sql> 
 +select books.* from books where (books,title like 'あ%'); 
 +select authors.* from authors where authors.id in (1,2,5,...); 
 +</code> 
 + 
 +author側に条件があるとjoinする(ただしオブジェクト形式の条件指定しかできな
 + 
 +<code ruby> 
 +books = Book 
 +        .where("books,title LIKE ?", "あ%"
 +        .includes(:author) 
 +        .where(author: {birth_year: 1987}) 
 + 
 +books.each { |book| puts book.author.name } 
 +</code> 
 + 
 +<code sql> 
 +select books.*, authors.* from books  
 +  left outer join authors on books.author_id = authors.id  
 +  where books.title LIKE 'あ%' and authors.birth_year = 1987; 
 +</code> 
rails/active_record.1264407705.txt.gz · 最終更新: 2010/01/25 08:21 by 127.0.0.1