Средства доступа ассоциаций, которые вы определяете с помощью has_many
, довольно сложны в ActiveRecord за сценой.Они фактически используют класс отражения для возврата прокси-объекта, который ведет себя как класс модели, но ограничивает его искатели внешним ключом (и, возможно, другими условиями).Если вы хотите углубиться в это, вы можете взглянуть на mirror.rb, association.rb, association / association_proxy.rb и association / association_collection.rb в гем ActiveRecord.
Однако вв конце концов, мы можем использовать средство доступа к ассоциации, как если бы это был сам класс, а ActiveRecord позаботится о том, чтобы передать требуемые дополнительные условия для поиска классов.
Это означает, что если вы вызываете Album.first.photos
, то позадиСцена ActiveRecord вызывает Photo.find
(с дополнительным условием для возврата только тех записей, которые имеют: album_id => Album.first.id).
Итак, если вы переопределите Photo.find
, он вернет ваш измененныйрезультаты также, если вы используете его через Album.first.photos
.Это волшебство ActiveRecord:)
Мой быстрый тест (запускался с Rails 2.3.8):
class Album < ActiveRecord::Base
has_many :photos
end
class Photo < ActiveRecord::Base
belongs_to :album
def self.find (*args)
puts "XXX running custom finder"
super
end
end
Консоль Rails:
> Photo.all
XXX running custom finder
Photo Load (0.4ms) SELECT * FROM "photos"
=> [#<Photo id: 1, album_id: 1>, … ]
> Album.first.photos
Album Load (0.4ms) SELECT * FROM "albums" LIMIT 1
XXX running custom finder
Photo Load (0.3ms) SELECT * FROM "photos" WHERE ("photos".album_id = 1)
=> [#<Photo id: 1, album_id: 1>, … ]