0

我一直在阅读 Rails 3 Way 并正在检查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]似乎有条件地加载了记录。

您知道何时访问数据库以检查数据库中是否存在记录吗?

4

1 回答 1

1

Rails 使用延迟加载和记忆。

这意味着b.chapters在您第一次调用 getter 之前不会加载任何章节。

之后,由于记忆化,破坏章节并不会改变include?测试。Rails 不会重新加载书中的章节。因此,它不会知道该章节不再存在于书中。

请注意include?(定义在Enumerable/Array对象上,但不直接在ActiveRelation对象上实现)会自动导致 Rails 将ActiveRelation对象强制book.chapters转换为数组。因此,include?将首先获取章节数组,然后检查该章节是否包含在数组中。

显式调用reload(在任何ActiveRecord对象上)强制 rails 重新加载该特定对象,以便丢弃书中章节的缓存,并重新加载实际的章节。

  • 您无法关闭记忆功能,除非reload在需要重新加载的任何地方调用。
  • 你可以通过使用来告诉 Rails 急切加载而不是延迟加载includes,例如。book = 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 回答