class OccamsRecord::EagerLoaders::PolymorphicBelongsTo

Eager loader for polymorphic belongs tos

Attributes

name[R]

@return [String] association name

Public Class Methods

new(ref, scope = nil, use: nil, as: nil, optimizer: nil, &builder) click to toggle source

@param ref [ActiveRecord::Association] the ActiveRecord association @param scope [Proc] a scope to apply to the query (optional). It will be passed an ActiveRecord::Relation on which you may call all the normal query hethods (select, where, etc) as well as any scopes you've defined on the model. @param use [Array<Module>] optional Module to include in the result class (single or array) @param as [Symbol] Load the association usign a different attribute name @param optimizer [Symbol] Only used for `through` associations. A no op here. @yield perform eager loading on this association (optional)

# File lib/occams-record/eager_loaders/polymorphic_belongs_to.rb, line 19
def initialize(ref, scope = nil, use: nil, as: nil, optimizer: nil, &builder)
  @ref, @scope, @use = ref, scope, use
  @name = (as || ref.name).to_s
  @foreign_type = @ref.foreign_type.to_sym
  @foreign_key = @ref.foreign_key.to_sym
  @eager_loaders = EagerLoaders::Context.new(nil, polymorphic: true)
  instance_exec(&builder) if builder
end

Public Instance Methods

run(rows, query_logger: nil, measurements: nil) click to toggle source

Run the query and merge the results into the given rows.

@param rows [Array<OccamsRecord::Results::Row>] Array of rows used to calculate the query. @param query_logger [Array<String>]

# File lib/occams-record/eager_loaders/polymorphic_belongs_to.rb, line 34
def run(rows, query_logger: nil, measurements: nil)
  query(rows) { |scope|
    eager_loaders = @eager_loaders.dup
    eager_loaders.model = scope.klass
    assoc_rows = Query.new(scope, use: @use, eager_loaders: eager_loaders, query_logger: query_logger, measurements: measurements).run
    merge! assoc_rows, rows
  }
  nil
end

Private Instance Methods

base_scope(model) click to toggle source
# File lib/occams-record/eager_loaders/polymorphic_belongs_to.rb, line 83
def base_scope(model)
  q = model.all
  q = q.instance_exec(&@ref.scope) if @ref.scope
  q = @scope.(q) if @scope
  q
end
merge!(assoc_rows_of_type, rows) click to toggle source

Merge associations of type N into rows of model N.

# File lib/occams-record/eager_loaders/polymorphic_belongs_to.rb, line 67
def merge!(assoc_rows_of_type, rows)
  return if assoc_rows_of_type.empty?
  type = assoc_rows_of_type[0].class.model_name
  rows_of_type = rows.select { |row|
    begin
      row.send(@foreign_type) == type
    rescue NoMethodError => e
      raise MissingColumnError.new(row, e.name)
    end
  }
  Merge.new(rows_of_type, name).
    single!(assoc_rows_of_type, {@ref.foreign_key.to_s => @ref.active_record_primary_key.to_s})
end
query(rows) { |q| ... } click to toggle source

Yield ActiveRecord::Relations to the given block, one for every “type” represented in the given rows.

@param rows [Array<OccamsRecord::Results::Row>] Array of rows used to calculate the query. @yield

# File lib/occams-record/eager_loaders/polymorphic_belongs_to.rb, line 52
def query(rows)
  rows_by_type = rows.group_by(&@foreign_type)
  rows_by_type.each do |type, rows_of_type|
    next if type.nil? or type == ""
    model = type.constantize
    ids = rows_of_type.map(&@foreign_key).uniq
    ids.sort! if $occams_record_test
    q = base_scope(model).where(@ref.active_record_primary_key => ids)
    yield q if ids.any?
  end
end