Class: ActiveRecord::Associations::Association

Inherits:
Object
  • Object
show all
Defined in:
activerecord/lib/active_record/associations/association.rb

Overview

Direct Known Subclasses

CollectionAssociation, SingularAssociation

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(owner, reflection) ⇒ Association

Returns a new instance of Association.



25
26
27
28
29
30
31
32
33
34
# File 'activerecord/lib/active_record/associations/association.rb', line 25

def initialize(owner, reflection)
  reflection.check_validity!

  @target = nil
  @owner, @reflection = owner, reflection
  @updated = false

  reset
  reset_scope
end

Instance Attribute Details

#ownerObject (readonly)

Returns the value of attribute owner



21
22
23
# File 'activerecord/lib/active_record/associations/association.rb', line 21

def owner
  @owner
end

#reflectionObject (readonly)

Returns the value of attribute reflection



21
22
23
# File 'activerecord/lib/active_record/associations/association.rb', line 21

def reflection
  @reflection
end

#targetObject

Returns the value of attribute target



21
22
23
# File 'activerecord/lib/active_record/associations/association.rb', line 21

def target
  @target
end

Instance Method Details

#aliased_table_nameObject

Returns the name of the table of the related class:

post.comments.aliased_table_name # => "comments"


40
41
42
# File 'activerecord/lib/active_record/associations/association.rb', line 40

def aliased_table_name
  reflection.klass.table_name
end

#association_scopeObject

The scope for this association.

Note that the association_scope is merged into the target_scope only when the scoped method is called. This is because at that point the call may be surrounded by scope.scoping { … } or with_scope { … } etc, which affects the scope which actually gets built.



96
97
98
99
100
# File 'activerecord/lib/active_record/associations/association.rb', line 96

def association_scope
  if klass
    @association_scope ||= AssociationScope.new(self).scope
  end
end

#interpolate(sql, record = nil) ⇒ Object



154
155
156
157
158
159
160
# File 'activerecord/lib/active_record/associations/association.rb', line 154

def interpolate(sql, record = nil)
  if sql.respond_to?(:to_proc)
    owner.send(:instance_exec, record, &sql)
  else
    sql
  end
end

#klassObject

This class of the target. belongs_to polymorphic overrides this to look at the polymorphic_type field on the owner.



116
117
118
# File 'activerecord/lib/active_record/associations/association.rb', line 116

def klass
  reflection.klass
end

#load_targetObject

Loads the target if needed and returns it.

This method is abstract in the sense that it relies on find_target, which is expected to be provided by descendants.

If the target is already loaded it is just returned. Thus, you can call load_target unconditionally to get the target.

ActiveRecord::RecordNotFound is rescued within the method, and it is not reraised. The proxy is reset and nil is the return value.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'activerecord/lib/active_record/associations/association.rb', line 136

def load_target
  if find_target?
    begin
      if IdentityMap.enabled? && association_class && association_class.respond_to?(:base_class)
        @target = IdentityMap.get(association_class, owner[reflection.foreign_key])
      end
    rescue NameError
      nil
    ensure
      @target ||= find_target
    end
  end
  loaded! unless loaded?
  target
rescue ActiveRecord::RecordNotFound
  reset
end

#loaded!Object

Asserts the target has been loaded setting the loaded flag to true.



65
66
67
68
# File 'activerecord/lib/active_record/associations/association.rb', line 65

def loaded!
  @loaded      = true
  @stale_state = stale_state
end

#loaded?Boolean

Has the target been already loaded?

Returns:

  • (Boolean)


60
61
62
# File 'activerecord/lib/active_record/associations/association.rb', line 60

def loaded?
  @loaded
end

#reloadObject

Reloads the target and returns self on success.



52
53
54
55
56
57
# File 'activerecord/lib/active_record/associations/association.rb', line 52

def reload
  reset
  reset_scope
  load_target
  self unless target.nil?
end

#resetObject

Resets the loaded flag to false and sets the target to nil.



45
46
47
48
49
# File 'activerecord/lib/active_record/associations/association.rb', line 45

def reset
  @loaded = false
  IdentityMap.remove(target) if IdentityMap.enabled? && target
  @target = nil
end

#reset_scopeObject



102
103
104
# File 'activerecord/lib/active_record/associations/association.rb', line 102

def reset_scope
  @association_scope = nil
end

#scopedObject



86
87
88
# File 'activerecord/lib/active_record/associations/association.rb', line 86

def scoped
  target_scope.merge(association_scope)
end

#set_inverse_instance(record) ⇒ Object

Set the inverse association, if possible



107
108
109
110
111
112
# File 'activerecord/lib/active_record/associations/association.rb', line 107

def set_inverse_instance(record)
  if record && invertible_for?(record)
    inverse = record.association(inverse_reflection_for(record).name)
    inverse.target = owner
  end
end

#stale_target?Boolean

The target is stale if the target no longer points to the record(s) that the relevant foreign_key(s) refers to. If stale, the association accessor method on the owner will reload the target. It’s up to subclasses to implement the state_state method if relevant.

Note that if the target has not been loaded, it is not considered stale.

Returns:

  • (Boolean)


76
77
78
# File 'activerecord/lib/active_record/associations/association.rb', line 76

def stale_target?
  loaded? && @stale_state != stale_state
end

#target_scopeObject

Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the through association’s scope)



122
123
124
# File 'activerecord/lib/active_record/associations/association.rb', line 122

def target_scope
  klass.scoped
end