class DuckRecord::Reflection::AssociationReflection

Holds all the metadata about an association as it was specified in the Active Record class.

Attributes

foreign_type[R]
parent_reflection[RW]
type[R]

Public Class Methods

new(name, scope, options, active_record) click to toggle source
# File lib/duck_record/reflection.rb, line 419
      def initialize(name, scope, options, active_record)
        super
        @type         = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
        @foreign_type = options[:foreign_type] || "#{name}_type"
        @constructable = calculate_constructable(macro, options)
        @association_scope_cache = {}
        @scope_lock = Mutex.new

        if options[:class_name] && options[:class_name].class == Class
          ActiveSupport::Deprecation.warn(<<-MSG.squish)
            Passing a class to the `class_name` is deprecated and will raise
            an ArgumentError in Rails 5.2. It eagerloads more classes than
            necessary and potentially creates circular dependencies.

            Please pass the class name as a string:
            `#{macro} :#{name}, class_name: '#{options[:class_name]}'`
          MSG
        end
      end

Public Instance Methods

active_record_primary_key() click to toggle source
# File lib/duck_record/reflection.rb, line 471
def active_record_primary_key
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
end
add_as_source(seed) click to toggle source
# File lib/duck_record/reflection.rb, line 555
def add_as_source(seed)
  seed
end
alias_candidate(name) click to toggle source
# File lib/duck_record/reflection.rb, line 380
def alias_candidate(name)
  "#{plural_name}_#{name}"
end
association_class() click to toggle source
# File lib/duck_record/reflection.rb, line 553
def association_class; raise NotImplementedError; end
association_foreign_key() click to toggle source
# File lib/duck_record/reflection.rb, line 458
def association_foreign_key
  @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
end
association_primary_key(klass = nil) click to toggle source

klass option is necessary to support loading polymorphic associations

# File lib/duck_record/reflection.rb, line 463
def association_primary_key(klass = nil)
  options[:primary_key] || primary_key(klass || self.klass)
end
association_primary_key_type() click to toggle source
# File lib/duck_record/reflection.rb, line 467
def association_primary_key_type
  klass.type_for_attribute(association_primary_key.to_s)
end
association_scope_cache(conn, owner) { || ... } click to toggle source
# File lib/duck_record/reflection.rb, line 439
def association_scope_cache(conn, owner)
  key = conn.prepared_statements
  @association_scope_cache[key] ||= @scope_lock.synchronize {
    @association_scope_cache[key] ||= yield
  }
end
belongs_to?() click to toggle source

Returns true if self is a belongs_to reflection.

# File lib/duck_record/reflection.rb, line 548
def belongs_to?; false; end
chain() click to toggle source
# File lib/duck_record/reflection.rb, line 384
def chain
  collect_join_chain
end
check_eager_loadable!()
Alias for: check_preloadable!
check_preloadable!() click to toggle source
# File lib/duck_record/reflection.rb, line 481
      def check_preloadable!
        return unless scope

        if scope.arity > 0
          raise ArgumentError, <<-MSG.squish
            The association scope '#{name}' is instance dependent (the scope
            block takes an argument). Preloading instance dependent scopes is
            not supported.
          MSG
        end
      end
Also aliased as: check_eager_loadable!
check_validity!() click to toggle source
# File lib/duck_record/reflection.rb, line 475
def check_validity!
  unless klass < ActiveRecord::Base
    raise ArgumentError, "#{klass} must be inherited from ActiveRecord::Base."
  end
end
collect_join_chain() click to toggle source

A chain of reflections from this one back to the owner. For more see the explanation in ThroughReflection.

# File lib/duck_record/reflection.rb, line 504
def collect_join_chain
  [self]
end
collection?() click to toggle source

Returns whether or not this association reflection is for a collection association. Returns true if the macro is either has_many or has_and_belongs_to_many, false otherwise.

# File lib/duck_record/reflection.rb, line 530
def collection?
  false
end
compute_class(name) click to toggle source
# File lib/duck_record/reflection.rb, line 408
def compute_class(name)
  active_record.send(:compute_type, name)
end
constraints() click to toggle source
# File lib/duck_record/reflection.rb, line 376
def constraints
  chain.map(&:scopes).flatten
end
extensions() click to toggle source
# File lib/duck_record/reflection.rb, line 559
def extensions
  Array(options[:extend])
end
foreign_key() click to toggle source
# File lib/duck_record/reflection.rb, line 454
def foreign_key
  @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
end
get_join_keys(association_klass) click to toggle source
# File lib/duck_record/reflection.rb, line 388
def get_join_keys(association_klass)
  JoinKeys.new(join_pk(association_klass), join_fk)
end
has_one?() click to toggle source

Returns true if self is a has_one reflection.

# File lib/duck_record/reflection.rb, line 551
def has_one?; false; end
has_scope?() click to toggle source
# File lib/duck_record/reflection.rb, line 518
def has_scope?
  scope
end
join_keys() click to toggle source
# File lib/duck_record/reflection.rb, line 347
def join_keys
  get_join_keys klass
end
join_table() click to toggle source
# File lib/duck_record/reflection.rb, line 450
def join_table
  @join_table ||= options[:join_table] || derive_join_table
end
klass() click to toggle source

Returns the target association's class.

class Author < ActiveRecord::Base
  has_many :books
end

Author.reflect_on_association(:books).klass
# => Book

Note: Do not call klass.new or klass.create to instantiate a new association object. Use build_association or create_association instead. This allows plugins to hook into association object creation.

# File lib/duck_record/reflection.rb, line 404
def klass
  @klass ||= compute_class(class_name)
end
macro() click to toggle source

Returns the macro type.

has_many :clients returns :has_many

# File lib/duck_record/reflection.rb, line 525
def macro; raise NotImplementedError; end
nested?() click to toggle source
# File lib/duck_record/reflection.rb, line 514
def nested?
  false
end
primary_key_type() click to toggle source
# File lib/duck_record/reflection.rb, line 341
def primary_key_type
  klass.type_for_attribute(klass.primary_key)
end
quoted_table_name() click to toggle source
# File lib/duck_record/reflection.rb, line 337
def quoted_table_name
  klass.quoted_table_name
end
scope_chain() click to toggle source
# File lib/duck_record/reflection.rb, line 357
def scope_chain
  chain.map(&:scopes)
end
scopes() click to toggle source

Returns a list of scopes that should be applied for this Reflection object when querying the database.

# File lib/duck_record/reflection.rb, line 353
def scopes
  scope ? [scope] : []
end
source_reflection() click to toggle source
# File lib/duck_record/reflection.rb, line 498
def source_reflection
  self
end
table_name() click to toggle source
# File lib/duck_record/reflection.rb, line 412
def table_name
  klass.table_name
end
validate?() click to toggle source

Returns whether or not the association should be validated as part of the parent's validation.

Unless you explicitly disable validation with validate: false, validation will take place when:

  • you explicitly enable validation; validate: true

  • you use autosave; autosave: true

  • the association is a has_many association

# File lib/duck_record/reflection.rb, line 543
def validate?
  !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
end

Protected Instance Methods

actual_source_reflection() click to toggle source
# File lib/duck_record/reflection.rb, line 565
def actual_source_reflection # FIXME: this is a horrible name
  self
end

Private Instance Methods

calculate_constructable(_macro, _options) click to toggle source
# File lib/duck_record/reflection.rb, line 579
def calculate_constructable(_macro, _options)
  false
end
derive_class_name() click to toggle source
# File lib/duck_record/reflection.rb, line 583
def derive_class_name
  class_name = name.to_s
  class_name = class_name.singularize if collection?
  class_name.camelize
end
derive_foreign_key() click to toggle source
# File lib/duck_record/reflection.rb, line 589
def derive_foreign_key
  if options[:as]
    "#{options[:as]}_id"
  else
    "#{name}_id"
  end
end
join_fk() click to toggle source
# File lib/duck_record/reflection.rb, line 575
def join_fk
  active_record_primary_key
end
join_pk(_) click to toggle source
# File lib/duck_record/reflection.rb, line 571
def join_pk(_)
  foreign_key
end
primary_key(klass) click to toggle source
# File lib/duck_record/reflection.rb, line 597
def primary_key(klass)
  klass.primary_key || raise(ActiveRecord::UnknownPrimaryKey.new(klass))
end