我在尝试预加载包含条件lambda的has_many关联时遇到NoMethodError。
Class Event < ActiveRecord::Base
belongs_to :user
end
Class CalendarDay < ActiveRecord::Base
belongs_to :user
has_many :events,
->(_day) {
where(
user_id: _day.user_id,
deleted_at: nil
)
},
autosave: false,
foreign_key: :date,
primary_key: :date,
end
days = CalendarDay.all.to_a
loader = ActiveRecord::Associations::Preloader.new
loader.preload(days, :events)
#NoMethodError: undefined method `user_id' for nil:NilClass
预加载器似乎只适用于没有条件lambda的关系。
有人有什么想法吗?这是ActiveRecord :: Associations :: Preloader类中的错误吗?
答案 0 :(得分:1)
如果要预加载关联,则可以使用条件,但是不会传递父记录(在本例中为_day),因为每个日期对象都会有所不同。
Activerecord需要提出一个查询来加载所有事件,并且当每个父对象的条件发生变化时,它不知道如何做到这一点(如果我的内存是,当你包含一个关联时也是如此)正确的)
答案 1 :(得分:0)
我喜欢一篇描述如何手动预加载的好文章。 http://mrbrdo.wordpress.com/2013/09/25/manually-preloading-associations-in-rails-using-custom-scopessql/
collection = CalendarDay.all
dates = collection.map(&:date)
user_ids = collection.map(&:user_id)
events = Event.where(
date: dates,
user_id: user_ids
).to_a
collection.each do |record|
association = record.association(:events)
association.loaded!
association.target.concat(
#events.where(
# user_id: record.user_id,
# date: record.date,
# deleted_at: nil
#)
events.find_all { |e|
e.user_id == record.user_id &&
e.date == record.date &&
e.deleted_at == nil
}
)
end
#No preload code.
Views: 1129.8ms | ActiveRecord: 409.8ms
#Cache active record relation then query for each day.
Views: 296.4ms | ActiveRecord: 198.6ms
#Run query and use find_by
Views: 290.2ms | ActiveRecord: 28.2ms