activerecord 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (122) hide show
  1. data/CHANGELOG +220 -91
  2. data/README.rdoc +3 -3
  3. data/examples/performance.rb +88 -109
  4. data/lib/active_record.rb +6 -2
  5. data/lib/active_record/aggregations.rb +22 -45
  6. data/lib/active_record/associations.rb +264 -991
  7. data/lib/active_record/associations/alias_tracker.rb +85 -0
  8. data/lib/active_record/associations/association.rb +231 -0
  9. data/lib/active_record/associations/association_scope.rb +120 -0
  10. data/lib/active_record/associations/belongs_to_association.rb +40 -60
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +15 -63
  12. data/lib/active_record/associations/builder/association.rb +53 -0
  13. data/lib/active_record/associations/builder/belongs_to.rb +85 -0
  14. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +63 -0
  16. data/lib/active_record/associations/builder/has_many.rb +65 -0
  17. data/lib/active_record/associations/builder/has_one.rb +63 -0
  18. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  19. data/lib/active_record/associations/collection_association.rb +524 -0
  20. data/lib/active_record/associations/collection_proxy.rb +125 -0
  21. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +27 -118
  22. data/lib/active_record/associations/has_many_association.rb +50 -79
  23. data/lib/active_record/associations/has_many_through_association.rb +98 -67
  24. data/lib/active_record/associations/has_one_association.rb +45 -115
  25. data/lib/active_record/associations/has_one_through_association.rb +21 -25
  26. data/lib/active_record/associations/join_dependency.rb +215 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +150 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_helper.rb +56 -0
  31. data/lib/active_record/associations/preloader.rb +177 -0
  32. data/lib/active_record/associations/preloader/association.rb +126 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/singular_association.rb +55 -0
  43. data/lib/active_record/associations/through_association.rb +80 -0
  44. data/lib/active_record/attribute_methods.rb +19 -5
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +9 -8
  46. data/lib/active_record/attribute_methods/dirty.rb +8 -2
  47. data/lib/active_record/attribute_methods/primary_key.rb +33 -13
  48. data/lib/active_record/attribute_methods/read.rb +17 -17
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -4
  50. data/lib/active_record/attribute_methods/write.rb +2 -1
  51. data/lib/active_record/autosave_association.rb +66 -45
  52. data/lib/active_record/base.rb +445 -273
  53. data/lib/active_record/callbacks.rb +24 -33
  54. data/lib/active_record/coders/yaml_column.rb +41 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +106 -13
  56. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +16 -2
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -12
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +16 -16
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +61 -22
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -273
  62. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -42
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +44 -25
  64. data/lib/active_record/connection_adapters/column.rb +268 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +686 -0
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +331 -88
  67. data/lib/active_record/connection_adapters/postgresql_adapter.rb +295 -267
  68. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -7
  69. data/lib/active_record/connection_adapters/sqlite_adapter.rb +108 -26
  70. data/lib/active_record/counter_cache.rb +7 -4
  71. data/lib/active_record/fixtures.rb +174 -192
  72. data/lib/active_record/identity_map.rb +131 -0
  73. data/lib/active_record/locking/optimistic.rb +20 -14
  74. data/lib/active_record/locking/pessimistic.rb +4 -4
  75. data/lib/active_record/log_subscriber.rb +24 -4
  76. data/lib/active_record/migration.rb +265 -144
  77. data/lib/active_record/migration/command_recorder.rb +103 -0
  78. data/lib/active_record/named_scope.rb +68 -25
  79. data/lib/active_record/nested_attributes.rb +58 -15
  80. data/lib/active_record/observer.rb +3 -7
  81. data/lib/active_record/persistence.rb +58 -38
  82. data/lib/active_record/query_cache.rb +25 -3
  83. data/lib/active_record/railtie.rb +21 -12
  84. data/lib/active_record/railties/console_sandbox.rb +6 -0
  85. data/lib/active_record/railties/databases.rake +147 -116
  86. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  87. data/lib/active_record/reflection.rb +176 -44
  88. data/lib/active_record/relation.rb +125 -49
  89. data/lib/active_record/relation/batches.rb +7 -5
  90. data/lib/active_record/relation/calculations.rb +50 -18
  91. data/lib/active_record/relation/finder_methods.rb +47 -26
  92. data/lib/active_record/relation/predicate_builder.rb +24 -21
  93. data/lib/active_record/relation/query_methods.rb +117 -101
  94. data/lib/active_record/relation/spawn_methods.rb +27 -20
  95. data/lib/active_record/result.rb +34 -0
  96. data/lib/active_record/schema.rb +5 -6
  97. data/lib/active_record/schema_dumper.rb +11 -13
  98. data/lib/active_record/serialization.rb +2 -2
  99. data/lib/active_record/serializers/xml_serializer.rb +10 -10
  100. data/lib/active_record/session_store.rb +8 -2
  101. data/lib/active_record/test_case.rb +9 -20
  102. data/lib/active_record/timestamp.rb +21 -9
  103. data/lib/active_record/transactions.rb +16 -15
  104. data/lib/active_record/validations.rb +21 -22
  105. data/lib/active_record/validations/associated.rb +3 -1
  106. data/lib/active_record/validations/uniqueness.rb +48 -58
  107. data/lib/active_record/version.rb +3 -3
  108. data/lib/rails/generators/active_record.rb +6 -0
  109. data/lib/rails/generators/active_record/migration/templates/migration.rb +10 -2
  110. data/lib/rails/generators/active_record/model/model_generator.rb +2 -1
  111. data/lib/rails/generators/active_record/model/templates/migration.rb +6 -5
  112. data/lib/rails/generators/active_record/model/templates/model.rb +2 -0
  113. data/lib/rails/generators/active_record/model/templates/module.rb +2 -0
  114. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  115. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +2 -1
  116. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +2 -2
  117. metadata +106 -77
  118. checksums.yaml +0 -7
  119. data/lib/active_record/association_preload.rb +0 -431
  120. data/lib/active_record/associations/association_collection.rb +0 -572
  121. data/lib/active_record/associations/association_proxy.rb +0 -304
  122. data/lib/active_record/associations/through_association_scope.rb +0 -160
@@ -1,304 +0,0 @@
1
- require 'active_support/core_ext/array/wrap'
2
-
3
- module ActiveRecord
4
- module Associations
5
- # = Active Record Associations
6
- #
7
- # This is the root class of all association proxies:
8
- #
9
- # AssociationProxy
10
- # BelongsToAssociation
11
- # HasOneAssociation
12
- # BelongsToPolymorphicAssociation
13
- # AssociationCollection
14
- # HasAndBelongsToManyAssociation
15
- # HasManyAssociation
16
- # HasManyThroughAssociation
17
- # HasOneThroughAssociation
18
- #
19
- # Association proxies in Active Record are middlemen between the object that
20
- # holds the association, known as the <tt>@owner</tt>, and the actual associated
21
- # object, known as the <tt>@target</tt>. The kind of association any proxy is
22
- # about is available in <tt>@reflection</tt>. That's an instance of the class
23
- # ActiveRecord::Reflection::AssociationReflection.
24
- #
25
- # For example, given
26
- #
27
- # class Blog < ActiveRecord::Base
28
- # has_many :posts
29
- # end
30
- #
31
- # blog = Blog.find(:first)
32
- #
33
- # the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
34
- # <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
35
- # the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
36
- #
37
- # This class has most of the basic instance methods removed, and delegates
38
- # unknown methods to <tt>@target</tt> via <tt>method_missing</tt>. As a
39
- # corner case, it even removes the +class+ method and that's why you get
40
- #
41
- # blog.posts.class # => Array
42
- #
43
- # though the object behind <tt>blog.posts</tt> is not an Array, but an
44
- # ActiveRecord::Associations::HasManyAssociation.
45
- #
46
- # The <tt>@target</tt> object is not \loaded until needed. For example,
47
- #
48
- # blog.posts.count
49
- #
50
- # is computed directly through SQL and does not trigger by itself the
51
- # instantiation of the actual post records.
52
- class AssociationProxy #:nodoc:
53
- alias_method :proxy_respond_to?, :respond_to?
54
- alias_method :proxy_extend, :extend
55
- delegate :to_param, :to => :proxy_target
56
- instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to_missing|proxy_/ }
57
-
58
- def initialize(owner, reflection)
59
- @owner, @reflection = owner, reflection
60
- @updated = false
61
- reflection.check_validity!
62
- Array.wrap(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
63
- reset
64
- end
65
-
66
- # Returns the owner of the proxy.
67
- def proxy_owner
68
- @owner
69
- end
70
-
71
- # Returns the reflection object that represents the association handled
72
- # by the proxy.
73
- def proxy_reflection
74
- @reflection
75
- end
76
-
77
- # Returns the \target of the proxy, same as +target+.
78
- def proxy_target
79
- @target
80
- end
81
-
82
- # Does the proxy or its \target respond to +symbol+?
83
- def respond_to?(*args)
84
- proxy_respond_to?(*args) || (load_target && @target.respond_to?(*args))
85
- end
86
-
87
- # Forwards <tt>===</tt> explicitly to the \target because the instance method
88
- # removal above doesn't catch it. Loads the \target if needed.
89
- def ===(other)
90
- load_target
91
- other === @target
92
- end
93
-
94
- # Returns the name of the table of the related class:
95
- #
96
- # post.comments.aliased_table_name # => "comments"
97
- #
98
- def aliased_table_name
99
- @reflection.klass.table_name
100
- end
101
-
102
- # Returns the SQL string that corresponds to the <tt>:conditions</tt>
103
- # option of the macro, if given, or +nil+ otherwise.
104
- def conditions
105
- @conditions ||= interpolate_sanitized_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions
106
- end
107
- alias :sql_conditions :conditions
108
-
109
- # Resets the \loaded flag to +false+ and sets the \target to +nil+.
110
- def reset
111
- @loaded = false
112
- @target = nil
113
- end
114
-
115
- # Loads the \target if not already loaded. Returns +self+ if the \target is present.
116
- def _load
117
- load_target unless loaded?
118
- self unless @target.nil?
119
- end
120
-
121
- # Reloads the \target and returns +self+ on success.
122
- def reload
123
- reset
124
- _load
125
- end
126
-
127
- # Has the \target been already \loaded?
128
- def loaded?
129
- @loaded
130
- end
131
-
132
- # Asserts the \target has been loaded setting the \loaded flag to +true+.
133
- def loaded
134
- @loaded = true
135
- end
136
-
137
- # Returns the target of this proxy, same as +proxy_target+.
138
- def target
139
- @target
140
- end
141
-
142
- # Sets the target of this proxy to <tt>\target</tt>, and the \loaded flag to +true+.
143
- def target=(target)
144
- @target = target
145
- loaded
146
- end
147
-
148
- # Forwards the call to the target. Loads the \target if needed.
149
- def inspect
150
- load_target
151
- @target.inspect
152
- end
153
-
154
- def send(method, *args)
155
- if proxy_respond_to?(method)
156
- super
157
- else
158
- load_target
159
- @target.send(method, *args)
160
- end
161
- end
162
-
163
- protected
164
- # Does the association have a <tt>:dependent</tt> option?
165
- def dependent?
166
- @reflection.options[:dependent]
167
- end
168
-
169
- def interpolate_sanitized_sql(sql, record = nil, sanitize_klass = @reflection.klass)
170
- @owner.send(:interpolate_sanitized_sql, sql, record, sanitize_klass)
171
- end
172
-
173
- def interpolate_and_sanitize_sql(sql, record = nil, sanitize_klass = @reflection.klass)
174
- @owner.send(:interpolate_and_sanitize_sql, sql, record, sanitize_klass)
175
- end
176
-
177
- # Forwards the call to the reflection class.
178
- def sanitize_sql(sql, table_name = @reflection.klass.table_name)
179
- @reflection.klass.send(:sanitize_sql, sql, table_name)
180
- end
181
-
182
- # Assigns the ID of the owner to the corresponding foreign key in +record+.
183
- # If the association is polymorphic the type of the owner is also set.
184
- def set_belongs_to_association_for(record)
185
- if @reflection.options[:as]
186
- record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
187
- record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
188
- else
189
- unless @owner.new_record?
190
- primary_key = @reflection.options[:primary_key] || :id
191
- record[@reflection.primary_key_name] = @owner.send(primary_key)
192
- end
193
- end
194
- end
195
-
196
- # Merges into +options+ the ones coming from the reflection.
197
- def merge_options_from_reflection!(options)
198
- options.reverse_merge!(
199
- :group => @reflection.options[:group],
200
- :having => @reflection.options[:having],
201
- :limit => @reflection.options[:limit],
202
- :offset => @reflection.options[:offset],
203
- :joins => @reflection.options[:joins],
204
- :include => @reflection.options[:include],
205
- :select => @reflection.options[:select],
206
- :readonly => @reflection.options[:readonly]
207
- )
208
- end
209
-
210
- # Forwards +with_scope+ to the reflection.
211
- def with_scope(*args, &block)
212
- @reflection.klass.send :with_scope, *args, &block
213
- end
214
-
215
- private
216
- # Forwards any missing method call to the \target.
217
- def method_missing(method, *args)
218
- if load_target
219
- unless @target.respond_to?(method)
220
- message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}"
221
- raise NoMethodError, message
222
- end
223
-
224
- if block_given?
225
- @target.send(method, *args) { |*block_args| yield(*block_args) }
226
- else
227
- @target.send(method, *args)
228
- end
229
- end
230
- end
231
-
232
- # Loads the \target if needed and returns it.
233
- #
234
- # This method is abstract in the sense that it relies on +find_target+,
235
- # which is expected to be provided by descendants.
236
- #
237
- # If the \target is already \loaded it is just returned. Thus, you can call
238
- # +load_target+ unconditionally to get the \target.
239
- #
240
- # ActiveRecord::RecordNotFound is rescued within the method, and it is
241
- # not reraised. The proxy is \reset and +nil+ is the return value.
242
- def load_target
243
- return nil unless defined?(@loaded)
244
-
245
- if !loaded? and (!@owner.new_record? || foreign_key_present)
246
- @target = find_target
247
- end
248
-
249
- @loaded = true
250
- @target
251
- rescue ActiveRecord::RecordNotFound
252
- reset
253
- end
254
-
255
- # Can be overwritten by associations that might have the foreign key
256
- # available for an association without having the object itself (and
257
- # still being a new record). Currently, only +belongs_to+ presents
258
- # this scenario (both vanilla and polymorphic).
259
- def foreign_key_present
260
- false
261
- end
262
-
263
- # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
264
- # the kind of the class of the associated objects. Meant to be used as
265
- # a sanity check when you are about to assign an associated record.
266
- def raise_on_type_mismatch(record)
267
- unless record.is_a?(@reflection.klass) || record.is_a?(@reflection.class_name.constantize)
268
- message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
269
- raise ActiveRecord::AssociationTypeMismatch, message
270
- end
271
- end
272
-
273
- if RUBY_VERSION < '1.9.2'
274
- # Array#flatten has problems with recursive arrays before Ruby 1.9.2.
275
- # Going one level deeper solves the majority of the problems.
276
- def flatten_deeper(array)
277
- array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
278
- end
279
- else
280
- def flatten_deeper(array)
281
- array.flatten
282
- end
283
- end
284
-
285
- # Returns the ID of the owner, quoted if needed.
286
- def owner_quoted_id
287
- @owner.quoted_id
288
- end
289
-
290
- def set_inverse_instance(record, instance)
291
- return if record.nil? || !we_can_set_the_inverse_on_this?(record)
292
- inverse_relationship = @reflection.inverse_of
293
- unless inverse_relationship.nil?
294
- record.send(:"set_#{inverse_relationship.name}_target", instance)
295
- end
296
- end
297
-
298
- # Override in subclasses
299
- def we_can_set_the_inverse_on_this?(record)
300
- false
301
- end
302
- end
303
- end
304
- end
@@ -1,160 +0,0 @@
1
- module ActiveRecord
2
- # = Active Record Through Association Scope
3
- module Associations
4
- module ThroughAssociationScope
5
-
6
- protected
7
-
8
- def construct_scope
9
- { :create => construct_owner_attributes(@reflection),
10
- :find => { :conditions => construct_conditions,
11
- :joins => construct_joins,
12
- :include => @reflection.options[:include] || @reflection.source_reflection.options[:include],
13
- :select => construct_select,
14
- :order => @reflection.options[:order],
15
- :limit => @reflection.options[:limit],
16
- :readonly => @reflection.options[:readonly],
17
- } }
18
- end
19
-
20
- # Build SQL conditions from attributes, qualified by table name.
21
- def construct_conditions
22
- table_name = @reflection.through_reflection.quoted_table_name
23
- conditions = construct_quoted_owner_attributes(@reflection.through_reflection).map do |attr, value|
24
- "#{table_name}.#{attr} = #{value}"
25
- end
26
- conditions << sql_conditions if sql_conditions
27
- "(" + conditions.join(') AND (') + ")"
28
- end
29
-
30
- # Associate attributes pointing to owner, quoted.
31
- def construct_quoted_owner_attributes(reflection)
32
- if as = reflection.options[:as]
33
- { "#{as}_id" => @owner.class.quote_value(
34
- @owner[reflection.active_record_primary_key],
35
- reflection.klass.columns_hash["#{as}_id"]),
36
- "#{as}_type" => reflection.klass.quote_value(
37
- @owner.class.base_class.name.to_s,
38
- reflection.klass.columns_hash["#{as}_type"]) }
39
- elsif reflection.macro == :belongs_to
40
- { reflection.klass.primary_key => @owner.class.quote_value(@owner[reflection.primary_key_name]) }
41
- else
42
- column = @owner.class.columns_hash[reflection.active_record_primary_key]
43
-
44
- { reflection.primary_key_name => @owner.class.quote_value(@owner[reflection.active_record_primary_key], column) }
45
- end
46
- end
47
-
48
- def construct_from
49
- @reflection.table_name
50
- end
51
-
52
- def construct_select(custom_select = nil)
53
- distinct = "DISTINCT " if @reflection.options[:uniq]
54
- selected = custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*"
55
- end
56
-
57
- def construct_joins(custom_joins = nil)
58
- polymorphic_join = nil
59
- if @reflection.source_reflection.macro == :belongs_to
60
- reflection_primary_key = @reflection.source_reflection.options[:primary_key] ||
61
- @reflection.klass.primary_key
62
- source_primary_key = @reflection.source_reflection.primary_key_name
63
- if @reflection.options[:source_type]
64
- polymorphic_join = "AND %s.%s = %s" % [
65
- @reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
66
- @owner.class.quote_value(@reflection.options[:source_type])
67
- ]
68
- end
69
- else
70
- reflection_primary_key = @reflection.source_reflection.primary_key_name
71
- source_primary_key = @reflection.source_reflection.options[:primary_key] ||
72
- @reflection.through_reflection.klass.primary_key
73
- if @reflection.source_reflection.options[:as]
74
- polymorphic_join = "AND %s.%s = %s" % [
75
- @reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
76
- @owner.class.quote_value(@reflection.through_reflection.klass.name)
77
- ]
78
- end
79
- end
80
-
81
- "INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [
82
- @reflection.through_reflection.quoted_table_name,
83
- @reflection.quoted_table_name, reflection_primary_key,
84
- @reflection.through_reflection.quoted_table_name, source_primary_key,
85
- polymorphic_join
86
- ]
87
- end
88
-
89
- # Construct attributes for associate pointing to owner.
90
- def construct_owner_attributes(reflection)
91
- if as = reflection.options[:as]
92
- { "#{as}_id" => @owner.id,
93
- "#{as}_type" => @owner.class.base_class.name.to_s }
94
- else
95
- { reflection.primary_key_name => @owner.id }
96
- end
97
- end
98
-
99
- # Construct attributes for :through pointing to owner and associate.
100
- def construct_join_attributes(associate)
101
- # TODO: revisit this to allow it for deletion, supposing dependent option is supported
102
- raise ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(@owner, @reflection) if [:has_one, :has_many].include?(@reflection.source_reflection.macro)
103
-
104
- join_attributes = construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.primary_key_name => associate.id)
105
-
106
- if @reflection.options[:source_type]
107
- join_attributes.merge!(@reflection.source_reflection.options[:foreign_type] => associate.class.base_class.name.to_s)
108
- end
109
-
110
- if @reflection.through_reflection.options[:conditions].is_a?(Hash)
111
- join_attributes.merge!(@reflection.through_reflection.options[:conditions])
112
- end
113
-
114
- join_attributes
115
- end
116
-
117
- def conditions
118
- @conditions = build_conditions unless defined?(@conditions)
119
- @conditions
120
- end
121
-
122
- def build_conditions
123
- association_conditions = @reflection.options[:conditions]
124
- through_conditions = build_through_conditions
125
- source_conditions = @reflection.source_reflection.options[:conditions]
126
- uses_sti = !@reflection.through_reflection.klass.descends_from_active_record?
127
-
128
- if association_conditions || through_conditions || source_conditions || uses_sti
129
- all = []
130
-
131
- [association_conditions, source_conditions].each do |conditions|
132
- all << interpolate_and_sanitize_sql(conditions) if conditions
133
- end
134
-
135
- all << through_conditions if through_conditions
136
- all << build_sti_condition if uses_sti
137
-
138
- all.map { |sql| "(#{sql})" } * ' AND '
139
- end
140
- end
141
-
142
- def build_through_conditions
143
- conditions = @reflection.through_reflection.options[:conditions]
144
- if conditions.is_a?(Hash)
145
- interpolate_and_sanitize_sql(conditions, nil, @reflection.through_reflection.klass).gsub(
146
- @reflection.quoted_table_name,
147
- @reflection.through_reflection.quoted_table_name)
148
- elsif conditions
149
- interpolate_and_sanitize_sql(conditions)
150
- end
151
- end
152
-
153
- def build_sti_condition
154
- @reflection.through_reflection.klass.send(:type_condition).to_sql
155
- end
156
-
157
- alias_method :sql_conditions, :conditions
158
- end
159
- end
160
- end