class AmsLazyRelationships::Loaders::Association

Lazy loads (has_one/has_many/has_many_through/belongs_to) ActiveRecord associations for ActiveRecord models

Attributes

association_name[R]
model_class_name[R]

Public Class Methods

new(model_class_name, association_name) click to toggle source

@param model_class_name [String] The name of AR class for which the

associations are loaded. E.g. When loading comment.blog_post
it'd be "BlogPost".

@param association_name [Symbol] The name of association being loaded

E.g. When loading comment.blog_post it'd be :blog_post
# File lib/ams_lazy_relationships/loaders/association.rb, line 15
def initialize(model_class_name, association_name)
  @model_class_name = model_class_name
  @association_name = association_name
end

Private Instance Methods

batch_key(_) click to toggle source
# File lib/ams_lazy_relationships/loaders/association.rb, line 39
def batch_key(_)
  @batch_key ||= "#{model_class_name}/#{association_name}"
end
load_data(records, loader) click to toggle source
# File lib/ams_lazy_relationships/loaders/association.rb, line 24
def load_data(records, loader)
  ::ActiveRecord::Associations::Preloader.new.preload(
    records_to_preload(records), association_name
  )

  data = []
  records.each do |r|
    value = r.public_send(association_name)
    data << value
    loader.call(r, value)
  end

  data = data.flatten.compact.uniq
end
records_to_preload(records) click to toggle source
# File lib/ams_lazy_relationships/loaders/association.rb, line 43
def records_to_preload(records)
  # It may happen that same record comes here twice (e.g. wrapped
  # in a decorator and non-wrapped). In this case Associations::Preloader
  # stores duplicated records in has_many relationships for some reason.
  # Calling uniq(&:id) solves the problem.
  #
  # One more case when duplicated records appear in has_many relationships
  # is the recent assignation to `accept_nested_attributes_for` setter.
  # ActiveRecord will not mark the association as `loaded` but in same
  # time will keep internal representation of the nested records created
  # by `accept_nested_attributes_for`. Then Associations::Preloader is
  # going to merge internal state of associated records with the same
  # records recently stored in DB. `r.association(association_name).reset`
  # effectively fixes that.
  records.
    uniq(&:id).
    reject { |r| r.association(association_name).loaded? }.
    each { |r| r.association(association_name).reset }
end