Когда 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, который возвращает хэш, где ключи являются результатом оценки блока, а значения являются исходным объектом. Так как вы, похоже, хотите найти страницы только по идентификатору, имеет смысл иметь хэш этих.
Ваше мнение о том, что вы должны быть более или менее интенсивным в отношении базы данных, является хорошим и заслуживает постоянного внимания. Если вы будете использовать большую часть возвращаемых данных, это будет иметь смысл. Если вы используете только крошечное подмножество данных, не имеет смысла загружать все данные для этих объектов, только для того, чтобы выбросить их через миллисекунды сборки мусора.