2012-09-06 127 views
0

我一直在閱讀的Rails 3路,並檢查CollectionAssociation.include?CollectionAssociation.include?檢查數據庫中是否存在記錄?

書中的行爲按說明:

檢查,看是否該協會 集合中存在提供的記錄,它仍然存在於底層數據庫 表中。

我做了幾個測試來檢查數據庫是否被檢查,但看起來像它沒有檢查。

> 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]似乎有條件地加載記錄。

當數據庫將被訪問以檢查數據庫中是否存在記錄時,您是否有任何想法?

回答

1

Rails同時使用延遲加載和memoization。

這意味着b.chapters直到您第一次調用getter時才加載任何章節。

之後,銷燬章節並沒有改變include?測試,因爲memoization。 Rails沒有重新載入書中的章節。因此,它不會知道書中不再存在該章。

注意include?(上Enumerable/Array對象中定義的,但不是ActiveRelation物體上直接實現)將自動使導軌固定到ActiveRelation對象book.chapters投射到陣列。因此,include?將首先獲取章節數組,然後檢查章節是否包含在數組中。

顯式調用reload(在任何ActiveRecord對象上)強制導軌重新加載該特定對象,以便廢棄書中各章的高速緩存並重新加載實際章節。

  • 您無法關閉備忘錄,除非您需要重新加載,否則請致電reload
  • 通過使用includes,例如,您可以告訴Rails熱切加載而不是延遲加載。 book = Book.includes(:chapters).first。這意味着Rails會在加載圖書的同時加載所有章節。

要刪除的章節,同時確保book.chapters是跟上時代的,你可以叫books.chapters.delete(book.chapters.last)books.chapter_ids.delete(book.chapter_ids.last)。使用這種方法,Rails不需要再次查詢數據庫以知道它不再處於集合中。

+0

謝謝你的深刻解答。這對理解很多事情確實有幫助。 –

+0

但問題仍然存在,在'include?'方法碰到數據庫的情況下? –

+0

當且僅當'章節'尚未被加載時,include?'(或任何其他作用於數組的方法)纔會觸發DB。除非由於延遲加載而第一次調用它,否則「章節」不會被加載。當我說「當你第一次打電話給我的時候」,我的意思是叫'book.chapters',這是一種「獲取」章節的方法。 – ronalchn

相關問題