rails:active_record
差分
このページの2つのバージョン間の差分を表示します。
次のリビジョン | 前のリビジョン | ||
rails:active_record [2010/01/25 08:21] – 作成 - 外部編集 127.0.0.1 | rails: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:: | User < ActiveRecord:: | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
end | end | ||
</ | </ | ||
行 147: | 行 146: | ||
検索時は | 検索時は | ||
- | LimitedItem.find(:all) | + | LimitedItem.all |
とすれば、 | とすれば、 | ||
select * from items where type = " | select * from items where type = " | ||
行 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:: | class Book < ActiveRecord:: | ||
行 216: | 行 217: | ||
end | end | ||
- | # left outer join | + | # 取得されたbookの数だけauthorを取得するSQLを実行(N+1クエリ問題) |
- | books = Book.find( | + | books = Book |
- | : | + | |
- | : | + | |
books.each { |book| puts book.author.name } | books.each { |book| puts book.author.name } | ||
</ | </ | ||
- | 関連テーブルの内容は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 ruby> | <code ruby> | ||
- | books = Book.find( | + | # authorも同時に取得(left outer joinを使用) |
- | : | + | books = Book |
- | :include => [: | + | |
- | : | + | |
books.each { |book| puts book.author.name } | books.each { |book| puts book.author.name } | ||
</ | </ | ||
- | joinsだけ指定すると関連テーブルを inner join するが、関連テーブルの内容は eager loading されない。joinsは関連オブジェクトが存在するレコードだけを取得するためのオプション、includeは関連オブジェクトをeager loadingのためのオプションであって役割が別なのである。 | ||
- | joinsとincludeオプションを両方指定したとき、古いwill_paginateプラグインを使っていると、SQLでレコード数をカウントする時に left outer join と inner join 両方含まれてしまう(結果はinner joinのみの場合と同じ)。これはwill_paginate | + | <code sql> |
+ | select books.*, authors.* from books | ||
+ | left outer join authors on books.author_id = authors.id where (books.title like ' | ||
+ | </ | ||
+ | |||
+ | left outer joinのため、 author が nil になる可能性があるので注意。inner joinで結合したい場合はjoinsを併用する | ||
+ | |||
+ | <code ruby> | ||
+ | # authorも同時に取得(inner joinを使用) | ||
+ | books = Book | ||
+ | .where(" | ||
+ | .eager_load(: | ||
+ | .joins(: | ||
+ | |||
+ | books.each { |book| puts book.author.name } | ||
+ | </ | ||
+ | |||
+ | <code sql> | ||
+ | select books.*, authors.* from books | ||
+ | inner join authors on books.author_id = authors.id where (books.title like ' | ||
+ | </ | ||
+ | |||
+ | |||
+ | joinsを単体で使用するとSQL発行時にauthorsテーブルをinner joinするがauthorデータの取得は行わない。検索条件にauthorを使いたいがauthorのデータは不要な場合に使用する | ||
+ | |||
+ | <code ruby> | ||
+ | # 著者名が「あ」で始まる書籍を取得 | ||
+ | books = Book | ||
+ | .where(" | ||
+ | .joins(: | ||
+ | </ | ||
+ | |||
+ | <code sql> | ||
+ | select books.* from books | ||
+ | | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== preload ==== | ||
+ | |||
+ | preloadはjoinせず、2つのSQLを発行して関連データを取得する。 | ||
+ | |||
+ | <code ruby> | ||
+ | # 著者名が「あ」で始まる書籍を取得 | ||
+ | books = Book | ||
+ | .where(" | ||
+ | .preload(: | ||
+ | |||
+ | books.each { |book| puts book.author.name } | ||
+ | </ | ||
+ | |||
+ | <code sql> | ||
+ | select books.* from books where (books, | ||
+ | select authors.* from authors where authors.id in (1, | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== includes ==== | ||
+ | |||
+ | includesは特殊で、通常はpreloadと同じ動きだが、結合テーブル側を検索条件に含めるとeager_loadに変わる | ||
+ | |||
+ | |||
+ | <code ruby> | ||
+ | books = Book | ||
+ | .where(" | ||
+ | .includes(: | ||
+ | |||
+ | books.each { |book| puts book.author.name } | ||
+ | </ | ||
+ | |||
+ | <code sql> | ||
+ | select books.* from books where (books, | ||
+ | select authors.* from authors where authors.id in (1,2,5,...); | ||
+ | </ | ||
+ | |||
+ | author側に条件があるとjoinする(ただしオブジェクト形式での条件指定しかできない) | ||
+ | |||
+ | <code ruby> | ||
+ | books = Book | ||
+ | .where(" | ||
+ | .includes(: | ||
+ | .where(author: | ||
+ | |||
+ | books.each { |book| puts book.author.name } | ||
+ | </ | ||
+ | |||
+ | <code sql> | ||
+ | select books.*, authors.* from books | ||
+ | left outer join authors on books.author_id = authors.id | ||
+ | where books.title LIKE ' | ||
+ | </ |
rails/active_record.1264407705.txt.gz · 最終更新: 2010/01/25 08:21 by 127.0.0.1