Помогите мне разобраться с Rails - PullRequest
1 голос
/ 14 мая 2010

Я немного запутался в механике активной загрузки активной записи. Допустим, у модели Book много Pages, и я выбираю книгу, используя этот запрос:

@book = Book.find book_id, :include => :pages

Теперь это где я запутался. Насколько я понимаю, @book.pages уже загружен и не будет выполнять другой запрос. Но предположим, что я хочу найти конкретную страницу, что я буду делать?

@book.pages.find page_id

# OR...

@book.pages.to_ary.find{|p| p.id == page_id}

Прав ли я, полагая, что в первом примере будет выполнен другой запрос, и, следовательно, делает бесполезной загрузку бессмысленной или активная запись достаточно умна, чтобы знать, что ей не нужно выполнять другой запрос?

Кроме того, мой второй вопрос, есть ли аргумент, что в некоторых случаях интенсивная загрузка в базу данных более интенсивна, а иногда несколько небольших запросов будут более эффективными, чем один большой запрос?

Спасибо за ваши мысли.

1 Ответ

2 голосов
/ 14 мая 2010

Когда ActiveRecord активно загружает ассоциацию, то, что происходит глубоко в недрах вашего объекта, является устанавливаемой переменной экземпляра. Вот и все, никакой магии. Все методы, предоставляемые Enumerable и ActiveRecord :: AssociationProxy, просто смотрят на переменную экземпляра, чтобы узнать, была ли она загружена или нет, а затем продолжают свое дело.

Когда вы вызываете #find, вы не загружаете коллекцию: вы ищете конкретный экземпляр. Вы говорите не с самой коллекцией.

Ваш второй пример - путь, но я бы сделал это по-другому:

@book.pages.detect {|p| p.id == page_id}

В качестве альтернативы, и здесь я предполагаю кое-что о вашем приложении, я бы сделал это еще лучше:

class BooksController < ApplicationController
  def show
    @book = Book.find(params[:id], :include => :pages)
    @pages_by_id = @book.pages.index_by(&:id)
  end
end

# app/views/books/show.html.erb
Page: <%= @pages_by_id[page_id].number %>

Обратите внимание, что я использую #index_by, который возвращает хэш, где ключи являются результатом оценки блока, а значения являются исходным объектом. Так как вы, похоже, хотите найти страницы только по идентификатору, имеет смысл иметь хэш этих.

Ваше мнение о том, что вы должны быть более или менее интенсивным в отношении базы данных, является хорошим и заслуживает постоянного внимания. Если вы будете использовать большую часть возвращаемых данных, это будет иметь смысл. Если вы используете только крошечное подмножество данных, не имеет смысла загружать все данные для этих объектов, только для того, чтобы выбросить их через миллисекунды сборки мусора.

...