activerecord 4.1.0 → 4.2.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +776 -1330
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/association_relation.rb +4 -0
  6. data/lib/active_record/associations/alias_tracker.rb +14 -13
  7. data/lib/active_record/associations/association.rb +2 -2
  8. data/lib/active_record/associations/association_scope.rb +83 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +15 -4
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
  13. data/lib/active_record/associations/builder/has_many.rb +1 -1
  14. data/lib/active_record/associations/builder/has_one.rb +2 -2
  15. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  16. data/lib/active_record/associations/collection_association.rb +66 -29
  17. data/lib/active_record/associations/collection_proxy.rb +22 -26
  18. data/lib/active_record/associations/has_many_association.rb +65 -18
  19. data/lib/active_record/associations/has_many_through_association.rb +55 -27
  20. data/lib/active_record/associations/has_one_association.rb +0 -1
  21. data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
  22. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  23. data/lib/active_record/associations/join_dependency.rb +20 -12
  24. data/lib/active_record/associations/preloader/association.rb +34 -11
  25. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  26. data/lib/active_record/associations/preloader.rb +49 -59
  27. data/lib/active_record/associations/singular_association.rb +25 -4
  28. data/lib/active_record/associations/through_association.rb +23 -14
  29. data/lib/active_record/associations.rb +171 -42
  30. data/lib/active_record/attribute.rb +149 -0
  31. data/lib/active_record/attribute_assignment.rb +18 -10
  32. data/lib/active_record/attribute_decorators.rb +66 -0
  33. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  34. data/lib/active_record/attribute_methods/dirty.rb +98 -44
  35. data/lib/active_record/attribute_methods/primary_key.rb +14 -8
  36. data/lib/active_record/attribute_methods/query.rb +1 -1
  37. data/lib/active_record/attribute_methods/read.rb +22 -59
  38. data/lib/active_record/attribute_methods/serialization.rb +37 -147
  39. data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
  40. data/lib/active_record/attribute_methods/write.rb +14 -21
  41. data/lib/active_record/attribute_methods.rb +67 -94
  42. data/lib/active_record/attribute_set/builder.rb +86 -0
  43. data/lib/active_record/attribute_set.rb +77 -0
  44. data/lib/active_record/attributes.rb +139 -0
  45. data/lib/active_record/autosave_association.rb +45 -38
  46. data/lib/active_record/base.rb +10 -20
  47. data/lib/active_record/callbacks.rb +7 -7
  48. data/lib/active_record/coders/json.rb +13 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
  60. data/lib/active_record/connection_adapters/column.rb +28 -239
  61. data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
  62. data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
  63. data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
  64. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  65. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
  67. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  96. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
  97. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  98. data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
  99. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  100. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
  101. data/lib/active_record/connection_handling.rb +3 -3
  102. data/lib/active_record/core.rb +143 -32
  103. data/lib/active_record/counter_cache.rb +60 -7
  104. data/lib/active_record/enum.rb +10 -11
  105. data/lib/active_record/errors.rb +49 -27
  106. data/lib/active_record/explain.rb +1 -1
  107. data/lib/active_record/fixtures.rb +56 -70
  108. data/lib/active_record/gem_version.rb +2 -2
  109. data/lib/active_record/inheritance.rb +35 -10
  110. data/lib/active_record/integration.rb +4 -4
  111. data/lib/active_record/locking/optimistic.rb +35 -17
  112. data/lib/active_record/log_subscriber.rb +1 -1
  113. data/lib/active_record/migration/command_recorder.rb +19 -2
  114. data/lib/active_record/migration/join_table.rb +1 -1
  115. data/lib/active_record/migration.rb +52 -49
  116. data/lib/active_record/model_schema.rb +49 -57
  117. data/lib/active_record/nested_attributes.rb +7 -7
  118. data/lib/active_record/null_relation.rb +19 -5
  119. data/lib/active_record/persistence.rb +50 -31
  120. data/lib/active_record/query_cache.rb +3 -3
  121. data/lib/active_record/querying.rb +10 -7
  122. data/lib/active_record/railtie.rb +14 -11
  123. data/lib/active_record/railties/databases.rake +56 -54
  124. data/lib/active_record/readonly_attributes.rb +0 -1
  125. data/lib/active_record/reflection.rb +286 -102
  126. data/lib/active_record/relation/batches.rb +0 -1
  127. data/lib/active_record/relation/calculations.rb +39 -31
  128. data/lib/active_record/relation/delegation.rb +2 -2
  129. data/lib/active_record/relation/finder_methods.rb +80 -36
  130. data/lib/active_record/relation/merger.rb +25 -30
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
  132. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  133. data/lib/active_record/relation/predicate_builder.rb +11 -10
  134. data/lib/active_record/relation/query_methods.rb +141 -55
  135. data/lib/active_record/relation/spawn_methods.rb +3 -0
  136. data/lib/active_record/relation.rb +69 -30
  137. data/lib/active_record/result.rb +18 -7
  138. data/lib/active_record/sanitization.rb +12 -2
  139. data/lib/active_record/schema.rb +0 -1
  140. data/lib/active_record/schema_dumper.rb +58 -26
  141. data/lib/active_record/schema_migration.rb +11 -0
  142. data/lib/active_record/scoping/default.rb +8 -7
  143. data/lib/active_record/scoping/named.rb +4 -0
  144. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  145. data/lib/active_record/statement_cache.rb +95 -10
  146. data/lib/active_record/store.rb +19 -10
  147. data/lib/active_record/tasks/database_tasks.rb +73 -7
  148. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
  149. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  150. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  151. data/lib/active_record/timestamp.rb +11 -9
  152. data/lib/active_record/transactions.rb +37 -21
  153. data/lib/active_record/type/big_integer.rb +13 -0
  154. data/lib/active_record/type/binary.rb +50 -0
  155. data/lib/active_record/type/boolean.rb +30 -0
  156. data/lib/active_record/type/date.rb +46 -0
  157. data/lib/active_record/type/date_time.rb +43 -0
  158. data/lib/active_record/type/decimal.rb +40 -0
  159. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  160. data/lib/active_record/type/decorator.rb +14 -0
  161. data/lib/active_record/type/float.rb +19 -0
  162. data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
  163. data/lib/active_record/type/integer.rb +55 -0
  164. data/lib/active_record/type/mutable.rb +16 -0
  165. data/lib/active_record/type/numeric.rb +36 -0
  166. data/lib/active_record/type/serialized.rb +56 -0
  167. data/lib/active_record/type/string.rb +36 -0
  168. data/lib/active_record/type/text.rb +11 -0
  169. data/lib/active_record/type/time.rb +26 -0
  170. data/lib/active_record/type/time_value.rb +38 -0
  171. data/lib/active_record/type/type_map.rb +64 -0
  172. data/lib/active_record/type/unsigned_integer.rb +15 -0
  173. data/lib/active_record/type/value.rb +101 -0
  174. data/lib/active_record/type.rb +23 -0
  175. data/lib/active_record/validations/associated.rb +5 -3
  176. data/lib/active_record/validations/presence.rb +6 -4
  177. data/lib/active_record/validations/uniqueness.rb +11 -17
  178. data/lib/active_record/validations.rb +25 -19
  179. data/lib/active_record.rb +3 -0
  180. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  181. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
  182. data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +65 -10
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  end
24
24
 
25
25
  def size
26
- 0
26
+ calculate :size, nil
27
27
  end
28
28
 
29
29
  def empty?
@@ -43,18 +43,32 @@ module ActiveRecord
43
43
  end
44
44
 
45
45
  def count(*)
46
- 0
46
+ calculate :count, nil
47
47
  end
48
48
 
49
49
  def sum(*)
50
- 0
50
+ calculate :sum, nil
51
+ end
52
+
53
+ def average(*)
54
+ calculate :average, nil
55
+ end
56
+
57
+ def minimum(*)
58
+ calculate :minimum, nil
59
+ end
60
+
61
+ def maximum(*)
62
+ calculate :maximum, nil
51
63
  end
52
64
 
53
65
  def calculate(operation, _column_name, _options = {})
54
66
  # TODO: Remove _options argument as soon we remove support to
55
67
  # activerecord-deprecated_finders.
56
- if operation == :count
57
- 0
68
+ if [:count, :sum, :size].include? operation
69
+ group_values.any? ? Hash.new : 0
70
+ elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
71
+ Hash.new
58
72
  else
59
73
  nil
60
74
  end
@@ -36,8 +36,25 @@ module ActiveRecord
36
36
  end
37
37
  end
38
38
 
39
+ # Creates an object (or multiple objects) and saves it to the database,
40
+ # if validations pass. Raises a RecordInvalid error if validations fail,
41
+ # unlike Base#create.
42
+ #
43
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes.
44
+ # These describe which attributes to be created on the object, or
45
+ # multiple objects when given an Array of Hashes.
46
+ def create!(attributes = nil, &block)
47
+ if attributes.is_a?(Array)
48
+ attributes.collect { |attr| create!(attr, &block) }
49
+ else
50
+ object = new(attributes, &block)
51
+ object.save!
52
+ object
53
+ end
54
+ end
55
+
39
56
  # Given an attributes hash, +instantiate+ returns a new instance of
40
- # the appropriate class.
57
+ # the appropriate class. Accepts only keys as strings.
41
58
  #
42
59
  # For example, +Post.all+ may return Comments, Messages, and Emails
43
60
  # by storing the record's subclass in a +type+ attribute. By calling
@@ -46,10 +63,10 @@ module ActiveRecord
46
63
  #
47
64
  # See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
48
65
  # how this "single-table" inheritance mapping is implemented.
49
- def instantiate(record, column_types = {})
50
- klass = discriminate_class_for_record(record)
51
- column_types = klass.decorate_columns(column_types.dup)
52
- klass.allocate.init_with('attributes' => record, 'column_types' => column_types)
66
+ def instantiate(attributes, column_types = {})
67
+ klass = discriminate_class_for_record(attributes)
68
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
69
+ klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
53
70
  end
54
71
 
55
72
  private
@@ -122,7 +139,7 @@ module ActiveRecord
122
139
  # Attributes marked as readonly are silently ignored if the record is
123
140
  # being updated.
124
141
  def save!(*)
125
- create_or_update || raise(RecordNotSaved)
142
+ create_or_update || raise(RecordNotSaved.new(nil, self))
126
143
  end
127
144
 
128
145
  # Deletes the record in the database and freezes this instance to
@@ -149,7 +166,7 @@ module ActiveRecord
149
166
  # and <tt>destroy</tt> returns +false+. See
150
167
  # ActiveRecord::Callbacks for further details.
151
168
  def destroy
152
- raise ReadOnlyRecord if readonly?
169
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
153
170
  destroy_associations
154
171
  destroy_row if persisted?
155
172
  @destroyed = true
@@ -164,7 +181,7 @@ module ActiveRecord
164
181
  # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
165
182
  # ActiveRecord::Callbacks for further details.
166
183
  def destroy!
167
- destroy || raise(ActiveRecord::RecordNotDestroyed)
184
+ destroy || raise(ActiveRecord::RecordNotDestroyed, self)
168
185
  end
169
186
 
170
187
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -180,7 +197,6 @@ module ActiveRecord
180
197
  def becomes(klass)
181
198
  became = klass.new
182
199
  became.instance_variable_set("@attributes", @attributes)
183
- became.instance_variable_set("@attributes_cache", @attributes_cache)
184
200
  became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
185
201
  became.instance_variable_set("@new_record", new_record?)
186
202
  became.instance_variable_set("@destroyed", destroyed?)
@@ -214,6 +230,8 @@ module ActiveRecord
214
230
  #
215
231
  # This method raises an +ActiveRecord::ActiveRecordError+ if the
216
232
  # attribute is marked as readonly.
233
+ #
234
+ # See also +update_column+.
217
235
  def update_attribute(name, value)
218
236
  name = name.to_s
219
237
  verify_readonly_attribute(name)
@@ -269,7 +287,8 @@ module ActiveRecord
269
287
  # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
270
288
  # objects, or when at least one of the attributes is marked as readonly.
271
289
  def update_columns(attributes)
272
- raise ActiveRecordError, "cannot update on a new record object" unless persisted?
290
+ raise ActiveRecordError, "cannot update a new record" if new_record?
291
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
273
292
 
274
293
  attributes.each_key do |key|
275
294
  verify_readonly_attribute(key.to_s)
@@ -394,24 +413,24 @@ module ActiveRecord
394
413
  self.class.unscoped { self.class.find(id) }
395
414
  end
396
415
 
397
- @attributes.update(fresh_object.instance_variable_get('@attributes'))
398
-
399
- @column_types = self.class.column_types
400
- @column_types_override = fresh_object.instance_variable_get('@column_types_override')
401
- @attributes_cache = {}
416
+ @attributes = fresh_object.instance_variable_get('@attributes')
417
+ @new_record = false
402
418
  self
403
419
  end
404
420
 
405
421
  # Saves the record with the updated_at/on attributes set to the current time.
406
- # Please note that no validation is performed and only the +after_touch+
407
- # callback is executed.
408
- # If an attribute name is passed, that attribute is updated along with
409
- # updated_at/on attributes.
422
+ # Please note that no validation is performed and only the +after_touch+,
423
+ # +after_commit+ and +after_rollback+ callbacks are executed.
424
+ #
425
+ # If attribute names are passed, they are updated along with updated_at/on
426
+ # attributes.
410
427
  #
411
- # product.touch # updates updated_at/on
412
- # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
428
+ # product.touch # updates updated_at/on
429
+ # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
430
+ # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
413
431
  #
414
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
432
+ # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
433
+ # associated object.
415
434
  #
416
435
  # class Brake < ActiveRecord::Base
417
436
  # belongs_to :car, touch: true
@@ -430,11 +449,11 @@ module ActiveRecord
430
449
  # ball = Ball.new
431
450
  # ball.touch(:updated_at) # => raises ActiveRecordError
432
451
  #
433
- def touch(name = nil)
452
+ def touch(*names)
434
453
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
435
454
 
436
455
  attributes = timestamp_attributes_for_update_in_model
437
- attributes << name if name
456
+ attributes.concat(names)
438
457
 
439
458
  unless attributes.empty?
440
459
  current_time = current_time_from_proper_timezone
@@ -447,7 +466,7 @@ module ActiveRecord
447
466
 
448
467
  changes[self.class.locking_column] = increment_lock if locking_enabled?
449
468
 
450
- changed_attributes.except!(*changes.keys)
469
+ clear_attribute_changes(changes.keys)
451
470
  primary_key = self.class.primary_key
452
471
  self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
453
472
  else
@@ -468,7 +487,7 @@ module ActiveRecord
468
487
  def relation_for_destroy
469
488
  pk = self.class.primary_key
470
489
  column = self.class.columns_hash[pk]
471
- substitute = self.class.connection.substitute_at(column, 0)
490
+ substitute = self.class.connection.substitute_at(column)
472
491
 
473
492
  relation = self.class.unscoped.where(
474
493
  self.class.arel_table[pk].eq(substitute))
@@ -478,25 +497,25 @@ module ActiveRecord
478
497
  end
479
498
 
480
499
  def create_or_update
481
- raise ReadOnlyRecord if readonly?
482
- result = new_record? ? create_record : update_record
500
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
501
+ result = new_record? ? _create_record : _update_record
483
502
  result != false
484
503
  end
485
504
 
486
505
  # Updates the associated record with values matching those of the instance attributes.
487
506
  # Returns the number of affected rows.
488
- def update_record(attribute_names = @attributes.keys)
507
+ def _update_record(attribute_names = self.attribute_names)
489
508
  attributes_values = arel_attributes_with_values_for_update(attribute_names)
490
509
  if attributes_values.empty?
491
510
  0
492
511
  else
493
- self.class.unscoped.update_record attributes_values, id, id_was
512
+ self.class.unscoped._update_record attributes_values, id, id_was
494
513
  end
495
514
  end
496
515
 
497
516
  # Creates a record with values matching those of the instance attributes
498
517
  # and returns its id.
499
- def create_record(attribute_names = @attributes.keys)
518
+ def _create_record(attribute_names = self.attribute_names)
500
519
  attributes_values = arel_attributes_with_values_for_create(attribute_names)
501
520
 
502
521
  new_id = self.class.unscoped.insert attributes_values
@@ -1,4 +1,3 @@
1
-
2
1
  module ActiveRecord
3
2
  # = Active Record Query Cache
4
3
  class QueryCache
@@ -29,9 +28,10 @@ module ActiveRecord
29
28
  end
30
29
 
31
30
  def call(env)
32
- enabled = ActiveRecord::Base.connection.query_cache_enabled
31
+ connection = ActiveRecord::Base.connection
32
+ enabled = connection.query_cache_enabled
33
33
  connection_id = ActiveRecord::Base.connection_id
34
- ActiveRecord::Base.connection.enable_query_cache!
34
+ connection.enable_query_cache!
35
35
 
36
36
  response = @app.call(env)
37
37
  response[2] = Rack::BodyProxy.new(response[2]) do
@@ -37,15 +37,18 @@ module ActiveRecord
37
37
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
38
38
  def find_by_sql(sql, binds = [])
39
39
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
40
- column_types = {}
40
+ column_types = result_set.column_types.dup
41
+ columns_hash.each_key { |k| column_types.delete k }
42
+ message_bus = ActiveSupport::Notifications.instrumenter
41
43
 
42
- if result_set.respond_to? :column_types
43
- column_types = result_set.column_types
44
- else
45
- ActiveSupport::Deprecation.warn "the object returned from `select_all` must respond to `column_types`"
46
- end
44
+ payload = {
45
+ record_count: result_set.length,
46
+ class_name: name
47
+ }
47
48
 
48
- result_set.map { |record| instantiate(record, column_types) }
49
+ message_bus.instrument('instantiation.active_record', payload) do
50
+ result_set.map { |record| instantiate(record, column_types) }
51
+ end
49
52
  end
50
53
 
51
54
  # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
@@ -36,8 +36,6 @@ module ActiveRecord
36
36
  config.eager_load_namespaces << ActiveRecord
37
37
 
38
38
  rake_tasks do
39
- require "active_record/base"
40
-
41
39
  namespace :db do
42
40
  task :load_config do
43
41
  ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
@@ -116,17 +114,22 @@ module ActiveRecord
116
114
  # and then establishes the connection.
117
115
  initializer "active_record.initialize_database" do |app|
118
116
  ActiveSupport.on_load(:active_record) do
117
+ self.configurations = Rails.application.config.database_configuration
119
118
 
120
- class ActiveRecord::NoDatabaseError
121
- remove_possible_method :extend_message
122
- def extend_message(message)
123
- message << "Run `$ bin/rake db:create db:migrate` to create your database"
124
- message
125
- end
126
- end
119
+ begin
120
+ establish_connection
121
+ rescue ActiveRecord::NoDatabaseError
122
+ warn <<-end_warning
123
+ Oops - You have a database configured, but it doesn't exist yet!
127
124
 
128
- self.configurations = Rails.application.config.database_configuration
129
- establish_connection
125
+ Here's how to get started:
126
+
127
+ 1. Configure your database in config/database.yml.
128
+ 2. Run `bin/rake db:create` to create the database.
129
+ 3. Run `bin/rake db:setup` to load your database schema.
130
+ end_warning
131
+ raise
132
+ end
130
133
  end
131
134
  end
132
135
 
@@ -28,12 +28,20 @@ db_namespace = namespace :db do
28
28
  ActiveRecord::Tasks::DatabaseTasks.drop_current
29
29
  end
30
30
 
31
+ namespace :purge do
32
+ task :all => :load_config do
33
+ ActiveRecord::Tasks::DatabaseTasks.purge_all
34
+ end
35
+ end
36
+
37
+ # desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
38
+ task :purge => [:load_config] do
39
+ ActiveRecord::Tasks::DatabaseTasks.purge_current
40
+ end
41
+
31
42
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
32
43
  task :migrate => [:environment, :load_config] do
33
- ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
34
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
35
- ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
36
- end
44
+ ActiveRecord::Tasks::DatabaseTasks.migrate
37
45
  db_namespace['_dump'].invoke if ActiveRecord::Base.dump_schema_after_migration
38
46
  end
39
47
 
@@ -82,22 +90,21 @@ db_namespace = namespace :db do
82
90
 
83
91
  desc 'Display status of migrations'
84
92
  task :status => [:environment, :load_config] do
85
- unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
86
- puts 'Schema migrations table does not exist yet.'
87
- next # means "return" for rake task
93
+ unless ActiveRecord::SchemaMigration.table_exists?
94
+ abort 'Schema migrations table does not exist yet.'
88
95
  end
89
- db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
90
- db_list.map! { |version| "%.3d" % version }
91
- file_list = []
92
- ActiveRecord::Migrator.migrations_paths.each do |path|
93
- Dir.foreach(path) do |file|
94
- # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
95
- if match_data = /^(\d{3,})_(.+)\.rb$/.match(file)
96
- status = db_list.delete(match_data[1]) ? 'up' : 'down'
97
- file_list << [status, match_data[1], match_data[2].humanize]
96
+ db_list = ActiveRecord::SchemaMigration.normalized_versions
97
+
98
+ file_list =
99
+ ActiveRecord::Migrator.migrations_paths.flat_map do |path|
100
+ # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
101
+ Dir.foreach(path).grep(/^(\d{3,})_(.+)\.rb$/) do
102
+ version = ActiveRecord::SchemaMigration.normalize_migration_number($1)
103
+ status = db_list.delete(version) ? 'up' : 'down'
104
+ [status, version, $2.humanize]
105
+ end
98
106
  end
99
- end
100
- end
107
+
101
108
  db_list.map! do |version|
102
109
  ['up', version, '********** NO FILE **********']
103
110
  end
@@ -105,8 +112,8 @@ db_namespace = namespace :db do
105
112
  puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
106
113
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
107
114
  puts "-" * 50
108
- (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
109
- puts "#{migration[0].center(8)} #{migration[1].ljust(14)} #{migration[2]}"
115
+ (db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
116
+ puts "#{status.center(8)} #{version.ljust(14)} #{name}"
110
117
  end
111
118
  puts
112
119
  end
@@ -178,17 +185,22 @@ db_namespace = namespace :db do
178
185
  task :load => [:environment, :load_config] do
179
186
  require 'active_record/fixtures'
180
187
 
181
- base_dir = if ENV['FIXTURES_PATH']
182
- File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
183
- else
184
- ActiveRecord::Tasks::DatabaseTasks.fixtures_path
185
- end
188
+ base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
186
189
 
187
- fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
190
+ fixtures_dir = if ENV['FIXTURES_DIR']
191
+ File.join base_dir, ENV['FIXTURES_DIR']
192
+ else
193
+ base_dir
194
+ end
188
195
 
189
- (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
190
- ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_file)
191
- end
196
+ fixture_files = if ENV['FIXTURES']
197
+ ENV['FIXTURES'].split(',')
198
+ else
199
+ # The use of String#[] here is to support namespaced fixtures
200
+ Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
201
+ end
202
+
203
+ ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
192
204
  end
193
205
 
194
206
  # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
@@ -200,16 +212,11 @@ db_namespace = namespace :db do
200
212
 
201
213
  puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
202
214
 
203
- base_dir = if ENV['FIXTURES_PATH']
204
- File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
205
- else
206
- ActiveRecord::Tasks::DatabaseTasks.fixtures_path
207
- end
208
-
215
+ base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
209
216
 
210
217
  Dir["#{base_dir}/**/*.yml"].each do |file|
211
218
  if data = YAML::load(ERB.new(IO.read(file)).result)
212
- data.keys.each do |key|
219
+ data.each_key do |key|
213
220
  key_id = ActiveRecord::FixtureSet.identify(key)
214
221
 
215
222
  if key == label || key_id == id.to_i
@@ -234,7 +241,7 @@ db_namespace = namespace :db do
234
241
 
235
242
  desc 'Load a schema.rb file into the database'
236
243
  task :load => [:environment, :load_config] do
237
- ActiveRecord::Tasks::DatabaseTasks.load_schema(:ruby, ENV['SCHEMA'])
244
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
238
245
  end
239
246
 
240
247
  task :load_if_ruby => ['db:create', :environment] do
@@ -268,7 +275,8 @@ db_namespace = namespace :db do
268
275
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
269
276
  ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
270
277
 
271
- if ActiveRecord::Base.connection.supports_migrations?
278
+ if ActiveRecord::Base.connection.supports_migrations? &&
279
+ ActiveRecord::SchemaMigration.table_exists?
272
280
  File.open(filename, "a") do |f|
273
281
  f.puts ActiveRecord::Base.connection.dump_schema_information
274
282
  f.print "\n"
@@ -277,9 +285,9 @@ db_namespace = namespace :db do
277
285
  db_namespace['structure:dump'].reenable
278
286
  end
279
287
 
280
- # desc "Recreate the databases from the structure.sql file"
288
+ desc "Recreate the databases from the structure.sql file"
281
289
  task :load => [:environment, :load_config] do
282
- ActiveRecord::Tasks::DatabaseTasks.load_schema(:sql, ENV['DB_STRUCTURE'])
290
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
283
291
  end
284
292
 
285
293
  task :load_if_sql => ['db:create', :environment] do
@@ -297,7 +305,7 @@ db_namespace = namespace :db do
297
305
  end
298
306
 
299
307
  # desc "Recreate the test database from the current schema"
300
- task :load => %w(db:test:deprecated db:test:purge) do
308
+ task :load => %w(db:test:purge) do
301
309
  case ActiveRecord::Base.schema_format
302
310
  when :ruby
303
311
  db_namespace["test:load_schema"].invoke
@@ -307,12 +315,11 @@ db_namespace = namespace :db do
307
315
  end
308
316
 
309
317
  # desc "Recreate the test database from an existent schema.rb file"
310
- task :load_schema => %w(db:test:deprecated db:test:purge) do
318
+ task :load_schema => %w(db:test:purge) do
311
319
  begin
312
320
  should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
313
- ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
314
321
  ActiveRecord::Schema.verbose = false
315
- db_namespace["schema:load"].invoke
322
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
316
323
  ensure
317
324
  if should_reconnect
318
325
  ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
@@ -321,13 +328,8 @@ db_namespace = namespace :db do
321
328
  end
322
329
 
323
330
  # desc "Recreate the test database from an existent structure.sql file"
324
- task :load_structure => %w(db:test:deprecated db:test:purge) do
325
- begin
326
- ActiveRecord::Tasks::DatabaseTasks.current_config(:config => ActiveRecord::Base.configurations['test'])
327
- db_namespace["structure:load"].invoke
328
- ensure
329
- ActiveRecord::Tasks::DatabaseTasks.current_config(:config => nil)
330
- end
331
+ task :load_structure => %w(db:test:purge) do
332
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
331
333
  end
332
334
 
333
335
  # desc "Recreate the test database from a fresh schema"
@@ -347,12 +349,12 @@ db_namespace = namespace :db do
347
349
  task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure)
348
350
 
349
351
  # desc "Empty the test database"
350
- task :purge => %w(db:test:deprecated environment load_config) do
352
+ task :purge => %w(environment load_config) do
351
353
  ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
352
354
  end
353
355
 
354
356
  # desc 'Check for pending migrations and load the test schema'
355
- task :prepare => %w(db:test:deprecated environment load_config) do
357
+ task :prepare => %w(environment load_config) do
356
358
  unless ActiveRecord::Base.configurations.blank?
357
359
  db_namespace['test:load'].invoke
358
360
  end
@@ -366,7 +368,7 @@ namespace :railties do
366
368
  task :migrations => :'db:load_config' do
367
369
  to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
368
370
  railties = {}
369
- Rails.application.railties.each do |railtie|
371
+ Rails.application.migration_railties.each do |railtie|
370
372
  next unless to_load == :all || to_load.include?(railtie.railtie_name)
371
373
 
372
374
  if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
@@ -1,4 +1,3 @@
1
-
2
1
  module ActiveRecord
3
2
  module ReadonlyAttributes
4
3
  extend ActiveSupport::Concern