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
59
# File 'lib/active_record/associations/association_proxy.rb', line 54

def initialize(owner, reflection)
  @owner, @reflection = owner, reflection
  reflection.check_validity!
  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, &block) ⇒ Object (private)

Forwards any missing method call to the target.



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

def method_missing(method, *args, &block)
  if load_target
    if @target.respond_to?(method)
      @target.send(method, *args, &block)
    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.



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

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"


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

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.



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

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.



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

def inspect
  load_target
  @target.inspect
end

#loadedObject

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



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

def loaded
  @loaded = true
end

#loaded?Boolean

Has the target been already loaded?

Returns:

  • (Boolean)


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

def loaded?
  @loaded
end

#proxy_ownerObject

Returns the owner of the proxy.



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

def proxy_owner
  @owner
end

#proxy_reflectionObject

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



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

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.



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

def proxy_target
  @target
end

#reloadObject

Reloads the target and returns self on success.



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

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

#resetObject

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



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

def reset
  @loaded = false
  @target = nil
end

#respond_to?(*args) ⇒ Boolean

Does the proxy or its target respond to symbol?

Returns:

  • (Boolean)


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

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

#send(method, *args) ⇒ Object



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

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.



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

def target
  @target
end

#target=(target) ⇒ Object

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



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

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