module ActiveRecord module AttributeMethods module ClassMethods # Generates all the attribute related methods for columns in the database # accessors, mutators and query methods. def define_attribute_methods return false if @attribute_methods_generated # Use a mutex; we don't want two threads simultaneously trying to define # attribute methods. generated_attribute_methods.synchronize do return false if @attribute_methods_generated superclass.define_attribute_methods unless self == base_class columns_to_define = if defined?(calculated) && calculated.instance_variable_get('@calculations') calculated_keys = calculated.instance_variable_get('@calculations').keys column_names.reject { |c| calculated_keys.include? c.intern } else column_names end super(columns_to_define) @attribute_methods_generated = true end true end end end module Associations class JoinDependency attr_writer :calculated_columns def instantiate(result_set, aliases) primary_key = aliases.column_alias(join_root, join_root.primary_key) seen = Hash.new do |i, object_id| i[object_id] = Hash.new do |j, child_class| j[child_class] = {} end end model_cache = Hash.new { |h, klass| h[klass] = {} } parents = model_cache[join_root] column_aliases = aliases.column_aliases join_root message_bus = ActiveSupport::Notifications.instrumenter payload = { record_count: result_set.length, class_name: join_root.base_klass.name } message_bus.instrument('instantiation.active_record', payload) do result_set.each do |row_hash| parent = parents[row_hash[primary_key]] ||= join_root.instantiate(row_hash, column_aliases) @calculated_columns.each { |column| parent[column.right] = model[column.right] } construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases) end end parents.values end end end end