0

私はRails 3 Wayを読んでいて、の動作をチェックしていましたCollectionAssociation.include?

本の説明によると:

指定されたレコードが関連付けコレクションに存在するかどうか、および基になるデータベース テーブルにまだ存在するかどうかを確認します。

DBがチェックされているかどうかを確認するためにいくつかのテストを行いますが、チェックしていないようです。

> book = Book.first
=> #<Book id: 1, title: "Programming Ruby"...
> last_chapter = book.chapters.last
=> #<Chapter id: 2, title: "Chapter 2", book_id: 1, 
> b.chapters.include?(last_chapter)
=> true 
> last_chapter.destroy
  DELETE FROM "chapters" WHERE "chapters"."id" = ?  [["id", 2]]
=> #<Chapter id: 2, title: "Chapter 2", book_id: 1, 
> b.chapters.include?(last_chapter)
=> true         
> book.chapters.reload
=> [#<Chapter id: 1, title: "Chapter 1", book_id: 1,...]
> b.chapters.include?(last_chapter)
=> false 

ソースコードを確認したところ、load_target if options[:finder_sql]条件付きでレコードをロードしているように見える行が見つかりました。

レコードがDBに存在するかどうかを確認するためにDBがいつアクセスされるか知っていますか?

4

1 に答える 1

1

Rails は遅延読み込みとメモ化の両方を使用します。

これはb.chapters、ゲッターを最初に呼び出すまでチャプターをロードしないことを意味します。

その後、章を破棄してもinclude?、メモ化のため、テストは変更されません。Rails は、本にある章をリロードしません。したがって、章がブックに存在しなくなったことはわかりません。

( /オブジェクトでinclude?定義されているが、オブジェクトに直接実装されていない) により、Rails は自動的にオブジェクトを配列にキャストすることに注意してください。したがって、最初に章の配列を取得し、次に章が配列に含まれているかどうかを確認します。EnumerableArrayActiveRelationActiveRelationbook.chaptersinclude?

reload明示的に (任意のオブジェクトで)呼び出すActiveRecordと、レールはその特定のオブジェクトを強制的にリロードするため、ブック内の章のキャッシュが破棄され、実際の章が再ロードされます。

  • reloadリロードする必要があるすべての場所を呼び出す場合を除いて、メモ化をオフにすることはできません。
  • を使用して、レイジー ロードの代わりにイーガー ロードするように Rails に指示できますincludesbook = Book.includes(:chapters).first. これは、Rails が本をロードすると同時にすべての章をロードすることを意味します。

チャプタを削除するには、チャプタがbook.chapters最新であることを確認しながら、books.chapters.delete(book.chapters.last)またはを呼び出しますbooks.chapter_ids.delete(book.chapter_ids.last)。この方法を使用すると、Rails は、データベースがコレクションに含まれていないことを知るために、データベースに再度クエリを実行する必要がなくなります。

于 2012-09-06T07:35:11.333 に答える