Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/tags/rel_2-0-2/activerecord/lib/active_record/associations/association_proxy.rb

Revision 8347, 4.3 kB (checked in by bitsweat, 9 months ago)

post.comments.reload returns the association rather than the result of load_target. Closes #10438 [Fred Cheung]

Line 
1 module ActiveRecord
2   module Associations
3     class AssociationProxy #:nodoc:
4       attr_reader :reflection
5       alias_method :proxy_respond_to?, :respond_to?
6       alias_method :proxy_extend, :extend
7       delegate :to_param, :to => :proxy_target
8       instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ }
9
10       def initialize(owner, reflection)
11         @owner, @reflection = owner, reflection
12         Array(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
13         reset
14       end
15
16       def proxy_owner
17         @owner
18       end
19
20       def proxy_reflection
21         @reflection
22       end
23
24       def proxy_target
25         @target
26       end
27
28       def respond_to?(symbol, include_priv = false)
29         proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv))
30       end
31
32       # Explicitly proxy === because the instance method removal above
33       # doesn't catch it.
34       def ===(other)
35         load_target
36         other === @target
37       end
38
39       def aliased_table_name
40         @reflection.klass.table_name
41       end
42
43       def conditions
44         @conditions ||= interpolate_sql(sanitize_sql(@reflection.options[:conditions])) if @reflection.options[:conditions]
45       end
46       alias :sql_conditions :conditions
47
48       def reset
49         @loaded = false
50         @target = nil
51       end
52
53       def reload
54         reset
55         load_target
56         self unless @target.nil?
57       end
58
59       def loaded?
60         @loaded
61       end
62
63       def loaded
64         @loaded = true
65       end
66
67       def target
68         @target
69       end
70
71       def target=(target)
72         @target = target
73         loaded
74       end
75
76       def inspect
77         reload unless loaded?
78         @target.inspect
79       end
80
81       protected
82         def dependent?
83           @reflection.options[:dependent]
84         end
85
86         def quoted_record_ids(records)
87           records.map { |record| record.quoted_id }.join(',')
88         end
89
90         def interpolate_sql_options!(options, *keys)
91           keys.each { |key| options[key] &&= interpolate_sql(options[key]) }
92         end
93
94         def interpolate_sql(sql, record = nil)
95           @owner.send(:interpolate_sql, sql, record)
96         end
97
98         def sanitize_sql(sql)
99           @reflection.klass.send(:sanitize_sql, sql)
100         end
101
102         def set_belongs_to_association_for(record)
103           if @reflection.options[:as]
104             record["#{@reflection.options[:as]}_id"]   = @owner.id unless @owner.new_record?
105             record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
106           else
107             record[@reflection.primary_key_name] = @owner.id unless @owner.new_record?
108           end
109         end
110
111         def merge_options_from_reflection!(options)
112           options.reverse_merge!(
113             :group   => @reflection.options[:group],
114             :limit   => @reflection.options[:limit],
115             :offset  => @reflection.options[:offset],
116             :joins   => @reflection.options[:joins],
117             :include => @reflection.options[:include],
118             :select  => @reflection.options[:select]
119           )
120         end
121
122       private
123         def method_missing(method, *args, &block)
124           if load_target
125             @target.send(method, *args, &block)
126           end
127         end
128
129         def load_target
130           return nil unless defined?(@loaded)
131
132           if !loaded? and (!@owner.new_record? || foreign_key_present)
133             @target = find_target
134           end
135
136           @loaded = true
137           @target
138         rescue ActiveRecord::RecordNotFound
139           reset
140         end
141
142         # Can be overwritten by associations that might have the foreign key available for an association without
143         # having the object itself (and still being a new record). Currently, only belongs_to presents this scenario.
144         def foreign_key_present
145           false
146         end
147
148         def raise_on_type_mismatch(record)
149           unless record.is_a?(@reflection.klass)
150             raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.klass} expected, got #{record.class}"
151           end
152         end
153
154         # Array#flatten has problems with recursive arrays. Going one level deeper solves the majority of the problems.
155         def flatten_deeper(array)
156           array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
157         end
158     end
159   end
160 end
Note: See TracBrowser for help on using the browser.