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 · 最終更新: by 127.0.0.1