Class: ActiveRecord::Associations::Association

Inherits:
Object
  • Object
show all
Defined in:
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 '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)

:nodoc:



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

def owner
  @owner
end

#reflectionObject (readonly)

:nodoc:



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

def reflection
  @reflection
end

#targetObject

:nodoc:



21
22
23
# File '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 '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.



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

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

#interpolate(sql, record = nil) ⇒ Object



160
161
162
163
164
165
166
# File 'lib/active_record/associations/association.rb', line 160

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.



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

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 stale(the target no longer points to the record(s) that the relevant foreign_key(s) refers to.), force reload the target.

Otherwise 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.



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/active_record/associations/association.rb', line 140

def load_target
  if (@stale_state && stale_target?) || find_target?
    begin
      if IdentityMap.enabled? && association_class && association_class.respond_to?(:base_class)
        @target = IdentityMap.get(association_class, owner[reflection.foreign_key])
      elsif @stale_state && stale_target?
        @target = find_target
      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.



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

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

#loaded?Boolean

Has the target been already loaded?

Returns:

  • (Boolean)


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

def loaded?
  @loaded
end

#reloadObject

Reloads the target and returns self on success.



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

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
50
# File 'lib/active_record/associations/association.rb', line 45

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

#reset_scopeObject



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

def reset_scope
  @association_scope = nil
end

#scopedObject



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

def scoped
  target_scope.merge(association_scope)
end

#set_inverse_instance(record) ⇒ Object

Set the inverse association, if possible



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

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)


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

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)



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

def target_scope
  klass.scoped
end