Preload has_many associations with dynamic conditions

后端 未结 4 1991
旧巷少年郎
旧巷少年郎 2020-12-15 08:24

I have a Place model and an Event model. Places can have events that take place on a specific date.

How can I set up my associatio

相关标签:
4条回答
  • 2020-12-15 08:37

    To solve the dynamic date problem, have you considered:

    class Event < ActiveRecord::Base
    
      belongs_to :place
    
      scope :on_date, lambda {|the_date| where(start_date: the_date) }
      scope :on_or_after, lambda {|the_date| where('start_date >= ?', the_date) }
    end
    

    You could then do this:

    @place = Place.find(params[:id]) # let's say...
    @place.events.on_date(params[:chosen_date])
    

    You can incorporate the eager loading stuff that others have mentioned too.

    0 讨论(0)
  • 2020-12-15 08:37

    As I understand, you want to fetch all the places that has at least one event satisfying some condition, but places should be fetched with all events list even those which doesn't satisfy condition. You can't figure this is out with one simple query, but if you will use suquery then issue will done. Here is the solution:

    Place.includes(:events).where(id: Place.joins(:events).where("events.start_date > '#{time_in_the_future}'")).references(:events)
    

    There is one complex query will be constructed, but it do the things right.

    0 讨论(0)
  • 2020-12-15 09:01

    This seems to be the only solution that works:

    # 1st query: load places
    places = Place.all.to_a
    
    # 2nd query: load events for given places, matching the date condition
    events = Event.where(place: places.map(&:id)).where("start_date > '#{time_in_the_future}'")
    events_by_place_id = events.group_by(&:place_id)
    
    # 3: manually set the association
    places.each do |place|
      events = events_by_place_id[place.id] || []
    
      association = place.association(:events)
      association.loaded!
      association.target.concat(events)
      events.each { |event| association.set_inverse_instance(event) }
    end
    

    It's a bit hacky but it's quite easy to adapt to any situation where you might want to load an association using a separate query and then attach it to an existing object.

    All credit goes to https://mrbrdo.wordpress.com/2013/09/25/manually-preloading-associations-in-rails-using-custom-scopessql/

    0 讨论(0)
  • 2020-12-15 09:01

    I have mentioned in some cases includes doesn't properly select eager loading method. There is an explanation of how this method work http://blog.arkency.com/2013/12/rails4-preloading/ . You can directly call eager_load(:events) an I think it will load your AR objects without n+1 problem.

    0 讨论(0)
提交回复
热议问题