activerecord 4.1.15 → 4.2.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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2176
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/association_scope.rb +53 -21
  7. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  8. data/lib/active_record/associations/builder/association.rb +16 -5
  9. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  10. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  11. data/lib/active_record/associations/builder/has_one.rb +2 -2
  12. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  13. data/lib/active_record/associations/collection_association.rb +32 -44
  14. data/lib/active_record/associations/collection_proxy.rb +1 -10
  15. data/lib/active_record/associations/has_many_association.rb +60 -14
  16. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  17. data/lib/active_record/associations/has_one_association.rb +0 -1
  18. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  19. data/lib/active_record/associations/join_dependency.rb +7 -9
  20. data/lib/active_record/associations/preloader/association.rb +9 -5
  21. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/singular_association.rb +16 -1
  24. data/lib/active_record/associations/through_association.rb +6 -22
  25. data/lib/active_record/associations.rb +58 -33
  26. data/lib/active_record/attribute.rb +131 -0
  27. data/lib/active_record/attribute_assignment.rb +19 -11
  28. data/lib/active_record/attribute_decorators.rb +66 -0
  29. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  30. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  31. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  32. data/lib/active_record/attribute_methods/read.rb +14 -57
  33. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  34. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  35. data/lib/active_record/attribute_methods/write.rb +8 -23
  36. data/lib/active_record/attribute_methods.rb +53 -90
  37. data/lib/active_record/attribute_set/builder.rb +32 -0
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attributes.rb +122 -0
  40. data/lib/active_record/autosave_association.rb +11 -21
  41. data/lib/active_record/base.rb +9 -19
  42. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  43. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  45. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  46. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  47. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  48. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  49. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  50. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  51. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  52. data/lib/active_record/connection_adapters/column.rb +13 -244
  53. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  55. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  56. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  57. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  58. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  59. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  60. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  61. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  85. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  86. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  87. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  88. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  89. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  90. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  91. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  93. data/lib/active_record/connection_handling.rb +1 -1
  94. data/lib/active_record/core.rb +119 -22
  95. data/lib/active_record/counter_cache.rb +60 -6
  96. data/lib/active_record/enum.rb +9 -10
  97. data/lib/active_record/errors.rb +27 -26
  98. data/lib/active_record/explain.rb +1 -1
  99. data/lib/active_record/fixtures.rb +52 -45
  100. data/lib/active_record/gem_version.rb +3 -3
  101. data/lib/active_record/inheritance.rb +33 -8
  102. data/lib/active_record/integration.rb +4 -4
  103. data/lib/active_record/locking/optimistic.rb +34 -16
  104. data/lib/active_record/migration/command_recorder.rb +19 -2
  105. data/lib/active_record/migration/join_table.rb +1 -1
  106. data/lib/active_record/migration.rb +22 -32
  107. data/lib/active_record/model_schema.rb +39 -48
  108. data/lib/active_record/nested_attributes.rb +8 -18
  109. data/lib/active_record/persistence.rb +39 -22
  110. data/lib/active_record/query_cache.rb +3 -3
  111. data/lib/active_record/querying.rb +1 -8
  112. data/lib/active_record/railtie.rb +17 -10
  113. data/lib/active_record/railties/databases.rake +47 -42
  114. data/lib/active_record/readonly_attributes.rb +0 -1
  115. data/lib/active_record/reflection.rb +225 -92
  116. data/lib/active_record/relation/batches.rb +0 -2
  117. data/lib/active_record/relation/calculations.rb +28 -32
  118. data/lib/active_record/relation/delegation.rb +1 -1
  119. data/lib/active_record/relation/finder_methods.rb +42 -20
  120. data/lib/active_record/relation/merger.rb +0 -1
  121. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  122. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/query_methods.rb +98 -62
  125. data/lib/active_record/relation/spawn_methods.rb +6 -7
  126. data/lib/active_record/relation.rb +35 -11
  127. data/lib/active_record/result.rb +16 -9
  128. data/lib/active_record/sanitization.rb +8 -1
  129. data/lib/active_record/schema.rb +0 -1
  130. data/lib/active_record/schema_dumper.rb +51 -9
  131. data/lib/active_record/schema_migration.rb +4 -0
  132. data/lib/active_record/scoping/default.rb +5 -4
  133. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  134. data/lib/active_record/statement_cache.rb +79 -5
  135. data/lib/active_record/store.rb +5 -5
  136. data/lib/active_record/tasks/database_tasks.rb +37 -5
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  138. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  139. data/lib/active_record/timestamp.rb +9 -7
  140. data/lib/active_record/transactions.rb +35 -21
  141. data/lib/active_record/type/binary.rb +40 -0
  142. data/lib/active_record/type/boolean.rb +19 -0
  143. data/lib/active_record/type/date.rb +46 -0
  144. data/lib/active_record/type/date_time.rb +43 -0
  145. data/lib/active_record/type/decimal.rb +40 -0
  146. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  147. data/lib/active_record/type/float.rb +19 -0
  148. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  149. data/lib/active_record/type/integer.rb +23 -0
  150. data/lib/active_record/type/mutable.rb +16 -0
  151. data/lib/active_record/type/numeric.rb +36 -0
  152. data/lib/active_record/type/serialized.rb +51 -0
  153. data/lib/active_record/type/string.rb +36 -0
  154. data/lib/active_record/type/text.rb +11 -0
  155. data/lib/active_record/type/time.rb +26 -0
  156. data/lib/active_record/type/time_value.rb +38 -0
  157. data/lib/active_record/type/type_map.rb +48 -0
  158. data/lib/active_record/type/value.rb +101 -0
  159. data/lib/active_record/type.rb +20 -0
  160. data/lib/active_record/validations/uniqueness.rb +9 -23
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record.rb +2 -1
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -19,14 +19,22 @@ module ActiveRecord
19
19
  #
20
20
  # Person.group(:city).count
21
21
  # # => { 'Rome' => 5, 'Paris' => 3 }
22
- #
22
+ #
23
+ # If +count+ is used with +group+ for multiple columns, it returns a Hash whose
24
+ # keys are an array containing the individual values of each column and the value
25
+ # of each key would be the +count+.
26
+ #
27
+ # Article.group(:status, :category).count
28
+ # # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
29
+ # ["published", "business"]=>0, ["published", "technology"]=>2}
30
+ #
23
31
  # If +count+ is used with +select+, it will count the selected columns:
24
32
  #
25
33
  # Person.select(:age).count
26
34
  # # => counts the number of different age values
27
35
  #
28
36
  # Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
29
- # between databases. In invalid cases, an error from the databsae is thrown.
37
+ # between databases. In invalid cases, an error from the database is thrown.
30
38
  def count(column_name = nil, options = {})
31
39
  # TODO: Remove options argument as soon we remove support to
32
40
  # activerecord-deprecated_finders.
@@ -170,21 +178,7 @@ module ActiveRecord
170
178
  columns_hash.key?(cn) ? arel_table[cn] : cn
171
179
  }
172
180
  result = klass.connection.select_all(relation.arel, nil, bind_values)
173
- columns = result.columns.map do |key|
174
- klass.column_types.fetch(key) {
175
- result.column_types.fetch(key) { result.identity_type }
176
- }
177
- end
178
-
179
- result = result.rows.map do |values|
180
- values = result.columns.zip(values).map do |column_name, value|
181
- single_attr_hash = { column_name => value }
182
- klass.initialize_attributes(single_attr_hash).values.first
183
- end
184
-
185
- columns.zip(values).map { |column, value| column.type_cast value }
186
- end
187
- columns.one? ? result.map!(&:first) : result
181
+ result.cast_values(klass.column_types)
188
182
  end
189
183
  end
190
184
 
@@ -246,11 +240,14 @@ module ActiveRecord
246
240
 
247
241
  column_alias = column_name
248
242
 
243
+ bind_values = nil
244
+
249
245
  if operation == "count" && (relation.limit_value || relation.offset_value)
250
246
  # Shortcut when limit is zero.
251
247
  return 0 if relation.limit_value == 0
252
248
 
253
249
  query_builder = build_count_subquery(relation, column_name, distinct)
250
+ bind_values = query_builder.bind_values + relation.bind_values
254
251
  else
255
252
  column = aggregate_column(column_name)
256
253
 
@@ -260,13 +257,14 @@ module ActiveRecord
260
257
  relation.select_values = [select_value]
261
258
 
262
259
  query_builder = relation.arel
260
+ bind_values = query_builder.bind_values + relation.bind_values
263
261
  end
264
262
 
265
- result = @klass.connection.select_all(query_builder, nil, relation.bind_values)
263
+ result = @klass.connection.select_all(query_builder, nil, bind_values)
266
264
  row = result.first
267
265
  value = row && row.values.first
268
266
  column = result.column_types.fetch(column_alias) do
269
- column_for(column_name)
267
+ type_for(column_name)
270
268
  end
271
269
 
272
270
  type_cast_calculated_value(value, column, operation)
@@ -277,7 +275,7 @@ module ActiveRecord
277
275
 
278
276
  if group_attrs.first.respond_to?(:to_sym)
279
277
  association = @klass._reflect_on_association(group_attrs.first.to_sym)
280
- associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
278
+ associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
281
279
  group_fields = Array(associated ? association.foreign_key : group_attrs)
282
280
  else
283
281
  group_fields = group_attrs
@@ -329,14 +327,14 @@ module ActiveRecord
329
327
  Hash[calculated_data.map do |row|
330
328
  key = group_columns.map { |aliaz, col_name|
331
329
  column = calculated_data.column_types.fetch(aliaz) do
332
- column_for(col_name)
330
+ type_for(col_name)
333
331
  end
334
332
  type_cast_calculated_value(row[aliaz], column)
335
333
  }
336
334
  key = key.first if key.size == 1
337
335
  key = key_records[key] if associated
338
336
 
339
- column_type = calculated_data.column_types.fetch(aggregate_alias) { column_for(column_name) }
337
+ column_type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
340
338
  [key, type_cast_calculated_value(row[aggregate_alias], column_type, operation)]
341
339
  end]
342
340
  end
@@ -363,24 +361,20 @@ module ActiveRecord
363
361
  @klass.connection.table_alias_for(table_name)
364
362
  end
365
363
 
366
- def column_for(field)
364
+ def type_for(field)
367
365
  field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
368
- @klass.columns_hash[field_name]
366
+ @klass.type_for_attribute(field_name)
369
367
  end
370
368
 
371
- def type_cast_calculated_value(value, column, operation = nil)
369
+ def type_cast_calculated_value(value, type, operation = nil)
372
370
  case operation
373
371
  when 'count' then value.to_i
374
- when 'sum' then type_cast_using_column(value || 0, column)
372
+ when 'sum' then type.type_cast_from_database(value || 0)
375
373
  when 'average' then value.respond_to?(:to_d) ? value.to_d : value
376
- else type_cast_using_column(value, column)
374
+ else type.type_cast_from_database(value)
377
375
  end
378
376
  end
379
377
 
380
- def type_cast_using_column(value, column)
381
- column ? column.type_cast(value) : value
382
- end
383
-
384
378
  # TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
385
379
  def select_for_count
386
380
  if select_values.present?
@@ -396,9 +390,11 @@ module ActiveRecord
396
390
 
397
391
  aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
398
392
  relation.select_values = [aliased_column]
399
- subquery = relation.arel.as(subquery_alias)
393
+ arel = relation.arel
394
+ subquery = arel.as(subquery_alias)
400
395
 
401
396
  sm = Arel::SelectManager.new relation.engine
397
+ sm.bind_values = arel.bind_values
402
398
  select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
403
399
  sm.project(select_value).from(subquery)
404
400
  end
@@ -40,7 +40,7 @@ module ActiveRecord
40
40
  BLACKLISTED_ARRAY_METHODS = [
41
41
  :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
42
42
  :shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
43
- :keep_if, :pop, :shift, :delete_at, :select!
43
+ :keep_if, :pop, :shift, :delete_at, :compact, :select!
44
44
  ].to_set # :nodoc:
45
45
 
46
46
  delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
@@ -1,3 +1,5 @@
1
+ require 'active_support/deprecation'
2
+
1
3
  module ActiveRecord
2
4
  module FinderMethods
3
5
  ONE_AS_ONE = '1 AS one'
@@ -127,9 +129,9 @@ module ActiveRecord
127
129
  #
128
130
  def first(limit = nil)
129
131
  if limit
130
- find_nth_with_limit(offset_value, limit)
132
+ find_nth_with_limit(offset_index, limit)
131
133
  else
132
- find_nth(:first, offset_value)
134
+ find_nth(0, offset_index)
133
135
  end
134
136
  end
135
137
 
@@ -179,7 +181,7 @@ module ActiveRecord
179
181
  # Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
180
182
  # Person.where(["user_name = :u", { u: user_name }]).second
181
183
  def second
182
- find_nth(:second, offset_value ? offset_value + 1 : 1)
184
+ find_nth(1, offset_index)
183
185
  end
184
186
 
185
187
  # Same as +second+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -195,7 +197,7 @@ module ActiveRecord
195
197
  # Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
196
198
  # Person.where(["user_name = :u", { u: user_name }]).third
197
199
  def third
198
- find_nth(:third, offset_value ? offset_value + 2 : 2)
200
+ find_nth(2, offset_index)
199
201
  end
200
202
 
201
203
  # Same as +third+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -211,7 +213,7 @@ module ActiveRecord
211
213
  # Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
212
214
  # Person.where(["user_name = :u", { u: user_name }]).fourth
213
215
  def fourth
214
- find_nth(:fourth, offset_value ? offset_value + 3 : 3)
216
+ find_nth(3, offset_index)
215
217
  end
216
218
 
217
219
  # Same as +fourth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -227,7 +229,7 @@ module ActiveRecord
227
229
  # Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
228
230
  # Person.where(["user_name = :u", { u: user_name }]).fifth
229
231
  def fifth
230
- find_nth(:fifth, offset_value ? offset_value + 4 : 4)
232
+ find_nth(4, offset_index)
231
233
  end
232
234
 
233
235
  # Same as +fifth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -243,7 +245,7 @@ module ActiveRecord
243
245
  # Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
244
246
  # Person.where(["user_name = :u", { u: user_name }]).forty_two
245
247
  def forty_two
246
- find_nth(:forty_two, offset_value ? offset_value + 41 : 41)
248
+ find_nth(41, offset_index)
247
249
  end
248
250
 
249
251
  # Same as +forty_two+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
@@ -280,7 +282,12 @@ module ActiveRecord
280
282
  # Person.exists?(false)
281
283
  # Person.exists?
282
284
  def exists?(conditions = :none)
283
- conditions = conditions.id if Base === conditions
285
+ if Base === conditions
286
+ conditions = conditions.id
287
+ ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `exists?`." \
288
+ "Please pass the id of the object by calling `.id`"
289
+ end
290
+
284
291
  return false if !conditions
285
292
 
286
293
  relation = apply_join_dependency(self, construct_join_dependency)
@@ -292,10 +299,12 @@ module ActiveRecord
292
299
  when Array, Hash
293
300
  relation = relation.where(conditions)
294
301
  else
295
- relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
302
+ unless conditions == :none
303
+ relation = where(primary_key => conditions)
304
+ end
296
305
  end
297
306
 
298
- connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
307
+ connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false
299
308
  end
300
309
 
301
310
  # This method is called whenever no records are found with either a single
@@ -322,6 +331,10 @@ module ActiveRecord
322
331
 
323
332
  private
324
333
 
334
+ def offset_index
335
+ offset_value || 0
336
+ end
337
+
325
338
  def find_with_associations
326
339
  # NOTE: the JoinDependency constructed here needs to know about
327
340
  # any joins already present in `self`, so pass them in
@@ -344,7 +357,8 @@ module ActiveRecord
344
357
  if ActiveRecord::NullRelation === relation
345
358
  []
346
359
  else
347
- rows = connection.select_all(relation.arel, 'SQL', relation.bind_values.dup)
360
+ arel = relation.arel
361
+ rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
348
362
  join_dependency.instantiate(rows, aliases)
349
363
  end
350
364
  end
@@ -358,7 +372,7 @@ module ActiveRecord
358
372
  def construct_relation_for_association_calculations
359
373
  from = arel.froms.first
360
374
  if Arel::Table === from
361
- apply_join_dependency(self, construct_join_dependency(joins_values))
375
+ apply_join_dependency(self, construct_join_dependency)
362
376
  else
363
377
  # FIXME: as far as I can tell, `from` will always be an Arel::Table.
364
378
  # There are no tests that test this branch, but presumably it's
@@ -418,7 +432,11 @@ module ActiveRecord
418
432
  end
419
433
 
420
434
  def find_one(id)
421
- id = id.id if ActiveRecord::Base === id
435
+ if ActiveRecord::Base === id
436
+ id = id.id
437
+ ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `find`." \
438
+ "Please pass the id of the object by calling `.id`"
439
+ end
422
440
 
423
441
  column = columns_hash[primary_key]
424
442
  substitute = connection.substitute_at(column, bind_values.length)
@@ -461,20 +479,24 @@ module ActiveRecord
461
479
  end
462
480
  end
463
481
 
464
- def find_nth(ordinal, offset)
482
+ def find_nth(index, offset)
465
483
  if loaded?
466
- @records.send(ordinal)
484
+ @records[index]
467
485
  else
486
+ offset += index
468
487
  @offsets[offset] ||= find_nth_with_limit(offset, 1).first
469
488
  end
470
489
  end
471
490
 
472
491
  def find_nth_with_limit(offset, limit)
473
- if order_values.empty? && primary_key
474
- order(arel_table[primary_key].asc).limit(limit).offset(offset).to_a
475
- else
476
- limit(limit).offset(offset).to_a
477
- end
492
+ relation = if order_values.empty? && primary_key
493
+ order(arel_table[primary_key].asc)
494
+ else
495
+ self
496
+ end
497
+
498
+ relation = relation.offset(offset) unless offset.zero?
499
+ relation.limit(limit).to_a
478
500
  end
479
501
 
480
502
  def find_last
@@ -147,7 +147,6 @@ module ActiveRecord
147
147
  def merge_single_values
148
148
  relation.from_value = values[:from] unless relation.from_value
149
149
  relation.lock_value = values[:lock] unless relation.lock_value
150
- relation.reverse_order_value = values[:reverse_order]
151
150
 
152
151
  unless values[:create_with].blank?
153
152
  relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
@@ -2,28 +2,33 @@ module ActiveRecord
2
2
  class PredicateBuilder
3
3
  class ArrayHandler # :nodoc:
4
4
  def call(attribute, value)
5
+ return attribute.in([]) if value.empty?
6
+
5
7
  values = value.map { |x| x.is_a?(Base) ? x.id : x }
6
8
  ranges, values = values.partition { |v| v.is_a?(Range) }
9
+ nils, values = values.partition(&:nil?)
7
10
 
8
- values_predicate = if values.include?(nil)
9
- values = values.compact
10
-
11
+ values_predicate =
11
12
  case values.length
12
- when 0
13
- attribute.eq(nil)
14
- when 1
15
- attribute.eq(values.first).or(attribute.eq(nil))
16
- else
17
- attribute.in(values).or(attribute.eq(nil))
13
+ when 0 then NullPredicate
14
+ when 1 then attribute.eq(values.first)
15
+ else attribute.in(values)
18
16
  end
19
- else
20
- attribute.in(values)
17
+
18
+ unless nils.empty?
19
+ values_predicate = values_predicate.or(attribute.eq(nil))
21
20
  end
22
21
 
23
22
  array_predicates = ranges.map { |range| attribute.in(range) }
24
23
  array_predicates << values_predicate
25
24
  array_predicates.inject { |composite, predicate| composite.or(predicate) }
26
25
  end
26
+
27
+ module NullPredicate
28
+ def self.or(other)
29
+ other
30
+ end
31
+ end
27
32
  end
28
33
  end
29
34
  end
@@ -6,10 +6,6 @@ module ActiveRecord
6
6
  value = value.select(value.klass.arel_table[value.klass.primary_key])
7
7
  end
8
8
 
9
- value = value.dup
10
- value.where_values = value.where_values.map do |node|
11
- node.dup rescue node
12
- end
13
9
  attribute.in(value.arel.ast)
14
10
  end
15
11
  end
@@ -56,17 +56,11 @@ module ActiveRecord
56
56
  # For polymorphic relationships, find the foreign key and type:
57
57
  # PriceEstimate.where(estimate_of: treasure)
58
58
  if klass && reflection = klass._reflect_on_association(column.to_sym)
59
- base_class = polymorphic_base_class_from_value(value)
60
- if reflection.polymorphic? && base_class
59
+ if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value)
61
60
  queries << build(table[reflection.foreign_type], base_class)
62
61
  end
63
62
 
64
63
  column = reflection.foreign_key
65
-
66
- if base_class
67
- primary_key = reflection.association_primary_key(base_class)
68
- value = convert_value_to_association_ids(value, primary_key)
69
- end
70
64
  end
71
65
 
72
66
  queries << build(table[column], value)
@@ -119,8 +113,6 @@ module ActiveRecord
119
113
  register_handler(Relation, RelationHandler.new)
120
114
  register_handler(Array, ArrayHandler.new)
121
115
 
122
- private
123
-
124
116
  def self.build(attribute, value)
125
117
  handler_for(value).call(attribute, value)
126
118
  end
@@ -130,18 +122,5 @@ module ActiveRecord
130
122
  @handlers.detect { |klass, _| klass === object }.last
131
123
  end
132
124
  private_class_method :handler_for
133
-
134
- def self.convert_value_to_association_ids(value, primary_key)
135
- case value
136
- when Relation
137
- value.select(primary_key)
138
- when Array
139
- value.map { |v| convert_value_to_association_ids(v, primary_key) }
140
- when Base
141
- value.read_attribute(primary_key)
142
- else
143
- value
144
- end
145
- end
146
125
  end
147
126
  end