Class: ActiveRecord::Associations::AssociationProxy

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

Overview

This is the root class of all association proxies:

AssociationProxy
  BelongsToAssociation
    HasOneAssociation
  BelongsToPolymorphicAssociation
  AssociationCollection
    HasAndBelongsToManyAssociation
    HasManyAssociation
      HasManyThroughAssociation
         HasOneThroughAssociation

Association proxies in Active Record are middlemen between the object that holds the association, known as the @owner, and the actual associated object, known as the @target. The kind of association any proxy is about is available in @reflection. That’s an instance of the class ActiveRecord::Reflection::AssociationReflection.

For example, given

class Blog < ActiveRecord::Base
  has_many :posts
end

blog = Blog.find(:first)

the association proxy in blog.posts has the object in blog as @owner, the collection of its posts as @target, and the @reflection object represents a :has_many macro.

This class has most of the basic instance methods removed, and delegates unknown methods to @target via method_missing. As a corner case, it even removes the class method and that’s why you get

blog.posts.class # => Array

though the object behind blog.posts is not an Array, but an ActiveRecord::Associations::HasManyAssociation.

The @target object is not loaded until needed. For example,

blog.posts.count

is computed directly through SQL and does not trigger by itself the instantiation of the actual post records.

Instance Method Summary collapse

Constructor Details

#initialize(owner, reflection) ⇒ AssociationProxy

Returns a new instance of AssociationProxy.



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

def initialize(owner, reflection)
  @owner, @reflection = owner, reflection
  Array(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
  reset
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object (private)

Forwards any missing method call to the target.



211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/active_record/associations/association_proxy.rb', line 211

def method_missing(method, *args)
  if load_target
    if @target.respond_to?(method)
      if block_given?
        @target.send(method, *args)  { |*block_args| yield(*block_args) }
      else
        @target.send(method, *args)
      end
    else
      super
    end
  end
end

Instance Method Details

#===(other) ⇒ Object

Forwards === explicitly to the target because the instance method removal above doesn’t catch it. Loads the target if needed.



83
84
85
86
# File 'lib/active_record/associations/association_proxy.rb', line 83

def ===(other)
  load_target
  other === @target
end

#aliased_table_nameObject

Returns the name of the table of the related class:

post.comments.aliased_table_name # => "comments"


92
93
94
# File 'lib/active_record/associations/association_proxy.rb', line 92

def aliased_table_name
  @reflection.klass.table_name
end

#conditionsObject Also known as: sql_conditions

Returns the SQL string that corresponds to the :conditions option of the macro, if given, or nil otherwise.



98
99
100
# File 'lib/active_record/associations/association_proxy.rb', line 98

def conditions
  @conditions ||= interpolate_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions
end

#inspectObject

Forwards the call to the target. Loads the target if needed.



138
139
140
141
# File 'lib/active_record/associations/association_proxy.rb', line 138

def inspect
  load_target
  @target.inspect
end

#loadedObject

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



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

def loaded
  @loaded = true
end

#loaded?Boolean

Has the target been already loaded?

Returns:

  • (Boolean)


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

def loaded?
  @loaded
end

#proxy_ownerObject

Returns the owner of the proxy.



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

def proxy_owner
  @owner
end

#proxy_reflectionObject

Returns the reflection object that represents the association handled by the proxy.



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

def proxy_reflection
  @reflection
end

#proxy_respond_to?Object

:nodoc:



49
# File 'lib/active_record/associations/association_proxy.rb', line 49

alias_method :proxy_respond_to?, :respond_to?

#proxy_targetObject

Returns the target of the proxy, same as target.



72
73
74
# File 'lib/active_record/associations/association_proxy.rb', line 72

def proxy_target
  @target
end

#reloadObject

Reloads the target and returns self on success.



110
111
112
113
114
# File 'lib/active_record/associations/association_proxy.rb', line 110

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

#resetObject

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



104
105
106
107
# File 'lib/active_record/associations/association_proxy.rb', line 104

def reset
  @loaded = false
  @target = nil
end

#respond_to?(*args) ⇒ Boolean

Does the proxy or its target respond to symbol?

Returns:

  • (Boolean)


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

def respond_to?(*args)
  proxy_respond_to?(*args) || (load_target && @target.respond_to?(*args))
end

#send(method, *args) ⇒ Object



143
144
145
146
147
148
149
150
# File 'lib/active_record/associations/association_proxy.rb', line 143

def send(method, *args)
  if proxy_respond_to?(method)
    super
  else
    load_target
    @target.send(method, *args)
  end
end

#targetObject

Returns the target of this proxy, same as proxy_target.



127
128
129
# File 'lib/active_record/associations/association_proxy.rb', line 127

def target
  @target
end

#target=(target) ⇒ Object

Sets the target of this proxy to \target, and the loaded flag to true.



132
133
134
135
# File 'lib/active_record/associations/association_proxy.rb', line 132

def target=(target)
  @target = target
  loaded
end