activerecord 4.1.8 → 4.2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1165 -1591
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +15 -8
  5. data/lib/active_record/association_relation.rb +13 -0
  6. data/lib/active_record/associations/alias_tracker.rb +3 -12
  7. data/lib/active_record/associations/association.rb +16 -4
  8. data/lib/active_record/associations/association_scope.rb +84 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
  14. data/lib/active_record/associations/builder/has_many.rb +1 -1
  15. data/lib/active_record/associations/builder/has_one.rb +2 -2
  16. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  17. data/lib/active_record/associations/collection_association.rb +87 -30
  18. data/lib/active_record/associations/collection_proxy.rb +33 -35
  19. data/lib/active_record/associations/foreign_association.rb +11 -0
  20. data/lib/active_record/associations/has_many_association.rb +83 -22
  21. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  22. data/lib/active_record/associations/has_one_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  24. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -12
  26. data/lib/active_record/associations/preloader/association.rb +14 -10
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +37 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +16 -12
  31. data/lib/active_record/associations.rb +158 -49
  32. data/lib/active_record/attribute.rb +163 -0
  33. data/lib/active_record/attribute_assignment.rb +20 -12
  34. data/lib/active_record/attribute_decorators.rb +66 -0
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  37. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  38. data/lib/active_record/attribute_methods/query.rb +1 -1
  39. data/lib/active_record/attribute_methods/read.rb +22 -59
  40. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +57 -95
  44. data/lib/active_record/attribute_set/builder.rb +106 -0
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attributes.rb +147 -0
  47. data/lib/active_record/autosave_association.rb +30 -12
  48. data/lib/active_record/base.rb +13 -24
  49. data/lib/active_record/callbacks.rb +6 -6
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
  62. data/lib/active_record/connection_adapters/column.rb +29 -240
  63. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
  66. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  67. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  69. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  101. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  103. data/lib/active_record/connection_handling.rb +1 -1
  104. data/lib/active_record/core.rb +163 -40
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +10 -12
  107. data/lib/active_record/errors.rb +53 -30
  108. data/lib/active_record/explain.rb +1 -1
  109. data/lib/active_record/explain_subscriber.rb +1 -1
  110. data/lib/active_record/fixtures.rb +62 -74
  111. data/lib/active_record/gem_version.rb +4 -4
  112. data/lib/active_record/inheritance.rb +35 -10
  113. data/lib/active_record/integration.rb +4 -4
  114. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  115. data/lib/active_record/locking/optimistic.rb +46 -26
  116. data/lib/active_record/migration/command_recorder.rb +19 -2
  117. data/lib/active_record/migration/join_table.rb +1 -1
  118. data/lib/active_record/migration.rb +79 -47
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +18 -8
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +48 -27
  123. data/lib/active_record/query_cache.rb +3 -3
  124. data/lib/active_record/querying.rb +10 -7
  125. data/lib/active_record/railtie.rb +19 -14
  126. data/lib/active_record/railties/databases.rake +55 -56
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +281 -117
  129. data/lib/active_record/relation/batches.rb +0 -1
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/delegation.rb +1 -1
  132. data/lib/active_record/relation/finder_methods.rb +71 -48
  133. data/lib/active_record/relation/merger.rb +39 -29
  134. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  135. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  136. data/lib/active_record/relation/predicate_builder.rb +42 -12
  137. data/lib/active_record/relation/query_methods.rb +130 -73
  138. data/lib/active_record/relation/spawn_methods.rb +10 -3
  139. data/lib/active_record/relation.rb +57 -25
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -8
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +54 -28
  155. data/lib/active_record/type/big_integer.rb +13 -0
  156. data/lib/active_record/type/binary.rb +50 -0
  157. data/lib/active_record/type/boolean.rb +31 -0
  158. data/lib/active_record/type/date.rb +50 -0
  159. data/lib/active_record/type/date_time.rb +54 -0
  160. data/lib/active_record/type/decimal.rb +64 -0
  161. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  162. data/lib/active_record/type/decorator.rb +14 -0
  163. data/lib/active_record/type/float.rb +19 -0
  164. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  165. data/lib/active_record/type/integer.rb +59 -0
  166. data/lib/active_record/type/mutable.rb +16 -0
  167. data/lib/active_record/type/numeric.rb +36 -0
  168. data/lib/active_record/type/serialized.rb +62 -0
  169. data/lib/active_record/type/string.rb +40 -0
  170. data/lib/active_record/type/text.rb +11 -0
  171. data/lib/active_record/type/time.rb +26 -0
  172. data/lib/active_record/type/time_value.rb +38 -0
  173. data/lib/active_record/type/type_map.rb +64 -0
  174. data/lib/active_record/type/unsigned_integer.rb +15 -0
  175. data/lib/active_record/type/value.rb +110 -0
  176. data/lib/active_record/type.rb +23 -0
  177. data/lib/active_record/validations/associated.rb +5 -3
  178. data/lib/active_record/validations/presence.rb +5 -3
  179. data/lib/active_record/validations/uniqueness.rb +24 -20
  180. data/lib/active_record/validations.rb +25 -19
  181. data/lib/active_record.rb +5 -0
  182. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  183. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  184. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  185. metadata +66 -11
  186. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -36,6 +36,23 @@ 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
57
  # the appropriate class. Accepts only keys as strings.
41
58
  #
@@ -48,8 +65,8 @@ module ActiveRecord
48
65
  # how this "single-table" inheritance mapping is implemented.
49
66
  def instantiate(attributes, column_types = {})
50
67
  klass = discriminate_class_for_record(attributes)
51
- column_types = klass.decorate_columns(column_types.dup)
52
- klass.allocate.init_with('attributes' => attributes, 'column_types' => column_types)
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("Failed to save the record", self))
126
143
  end
127
144
 
128
145
  # Deletes the record in the database and freezes this instance to
@@ -149,8 +166,9 @@ 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
171
+ self.class.connection.add_transaction_record(self)
154
172
  destroy_row if persisted?
155
173
  @destroyed = true
156
174
  freeze
@@ -164,7 +182,7 @@ module ActiveRecord
164
182
  # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
165
183
  # ActiveRecord::Callbacks for further details.
166
184
  def destroy!
167
- destroy || raise(ActiveRecord::RecordNotDestroyed)
185
+ destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
168
186
  end
169
187
 
170
188
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -180,8 +198,8 @@ module ActiveRecord
180
198
  def becomes(klass)
181
199
  became = klass.new
182
200
  became.instance_variable_set("@attributes", @attributes)
183
- became.instance_variable_set("@attributes_cache", @attributes_cache)
184
- became.instance_variable_set("@changed_attributes", @changed_attributes) if defined?(@changed_attributes)
201
+ changed_attributes = @changed_attributes if defined?(@changed_attributes)
202
+ became.instance_variable_set("@changed_attributes", changed_attributes || {})
185
203
  became.instance_variable_set("@new_record", new_record?)
186
204
  became.instance_variable_set("@destroyed", destroyed?)
187
205
  became.instance_variable_set("@errors", errors)
@@ -214,6 +232,8 @@ module ActiveRecord
214
232
  #
215
233
  # This method raises an +ActiveRecord::ActiveRecordError+ if the
216
234
  # attribute is marked as readonly.
235
+ #
236
+ # See also +update_column+.
217
237
  def update_attribute(name, value)
218
238
  name = name.to_s
219
239
  verify_readonly_attribute(name)
@@ -269,7 +289,8 @@ module ActiveRecord
269
289
  # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
270
290
  # objects, or when at least one of the attributes is marked as readonly.
271
291
  def update_columns(attributes)
272
- raise ActiveRecordError, "cannot update on a new record object" unless persisted?
292
+ raise ActiveRecordError, "cannot update a new record" if new_record?
293
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
273
294
 
274
295
  attributes.each_key do |key|
275
296
  verify_readonly_attribute(key.to_s)
@@ -348,7 +369,7 @@ module ActiveRecord
348
369
  # # => #<Account id: 1, email: 'account@example.com'>
349
370
  #
350
371
  # Attributes are reloaded from the database, and caches busted, in
351
- # particular the associations cache.
372
+ # particular the associations cache and the QueryCache.
352
373
  #
353
374
  # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
354
375
  # is raised. Otherwise, in addition to the in-place modification the method
@@ -386,6 +407,7 @@ module ActiveRecord
386
407
  def reload(options = nil)
387
408
  clear_aggregation_cache
388
409
  clear_association_cache
410
+ self.class.connection.clear_query_cache
389
411
 
390
412
  fresh_object =
391
413
  if options && options[:lock]
@@ -394,25 +416,24 @@ module ActiveRecord
394
416
  self.class.unscoped { self.class.find(id) }
395
417
  end
396
418
 
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 = {}
402
- @new_record = false
419
+ @attributes = fresh_object.instance_variable_get('@attributes')
420
+ @new_record = false
403
421
  self
404
422
  end
405
423
 
406
424
  # Saves the record with the updated_at/on attributes set to the current time.
407
425
  # Please note that no validation is performed and only the +after_touch+,
408
426
  # +after_commit+ and +after_rollback+ callbacks are executed.
409
- # If an attribute name is passed, that attribute is updated along with
410
- # updated_at/on attributes.
411
427
  #
412
- # product.touch # updates updated_at/on
413
- # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
428
+ # If attribute names are passed, they are updated along with updated_at/on
429
+ # attributes.
430
+ #
431
+ # product.touch # updates updated_at/on
432
+ # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
433
+ # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
414
434
  #
415
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
435
+ # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
436
+ # associated object.
416
437
  #
417
438
  # class Brake < ActiveRecord::Base
418
439
  # belongs_to :car, touch: true
@@ -431,11 +452,11 @@ module ActiveRecord
431
452
  # ball = Ball.new
432
453
  # ball.touch(:updated_at) # => raises ActiveRecordError
433
454
  #
434
- def touch(name = nil)
455
+ def touch(*names)
435
456
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
436
457
 
437
458
  attributes = timestamp_attributes_for_update_in_model
438
- attributes << name if name
459
+ attributes.concat(names)
439
460
 
440
461
  unless attributes.empty?
441
462
  current_time = current_time_from_proper_timezone
@@ -448,7 +469,7 @@ module ActiveRecord
448
469
 
449
470
  changes[self.class.locking_column] = increment_lock if locking_enabled?
450
471
 
451
- changed_attributes.except!(*changes.keys)
472
+ clear_attribute_changes(changes.keys)
452
473
  primary_key = self.class.primary_key
453
474
  self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
454
475
  else
@@ -469,7 +490,7 @@ module ActiveRecord
469
490
  def relation_for_destroy
470
491
  pk = self.class.primary_key
471
492
  column = self.class.columns_hash[pk]
472
- substitute = self.class.connection.substitute_at(column, 0)
493
+ substitute = self.class.connection.substitute_at(column)
473
494
 
474
495
  relation = self.class.unscoped.where(
475
496
  self.class.arel_table[pk].eq(substitute))
@@ -479,14 +500,14 @@ module ActiveRecord
479
500
  end
480
501
 
481
502
  def create_or_update
482
- raise ReadOnlyRecord if readonly?
503
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
483
504
  result = new_record? ? _create_record : _update_record
484
505
  result != false
485
506
  end
486
507
 
487
508
  # Updates the associated record with values matching those of the instance attributes.
488
509
  # Returns the number of affected rows.
489
- def _update_record(attribute_names = @attributes.keys)
510
+ def _update_record(attribute_names = self.attribute_names)
490
511
  attributes_values = arel_attributes_with_values_for_update(attribute_names)
491
512
  if attributes_values.empty?
492
513
  0
@@ -497,7 +518,7 @@ module ActiveRecord
497
518
 
498
519
  # Creates a record with values matching those of the instance attributes
499
520
  # and returns its id.
500
- def _create_record(attribute_names = @attributes.keys)
521
+ def _create_record(attribute_names = self.attribute_names)
501
522
  attributes_values = arel_attributes_with_values_for_create(attribute_names)
502
523
 
503
524
  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
@@ -59,8 +57,10 @@ module ActiveRecord
59
57
  console do |app|
60
58
  require "active_record/railties/console_sandbox" if app.sandbox?
61
59
  require "active_record/base"
62
- console = ActiveSupport::Logger.new(STDERR)
63
- Rails.logger.extend ActiveSupport::Logger.broadcast console
60
+ unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDERR, STDOUT)
61
+ console = ActiveSupport::Logger.new(STDERR)
62
+ Rails.logger.extend ActiveSupport::Logger.broadcast console
63
+ end
64
64
  end
65
65
 
66
66
  runner do
@@ -116,17 +116,22 @@ module ActiveRecord
116
116
  # and then establishes the connection.
117
117
  initializer "active_record.initialize_database" do |app|
118
118
  ActiveSupport.on_load(:active_record) do
119
+ self.configurations = Rails.application.config.database_configuration
119
120
 
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
121
+ begin
122
+ establish_connection
123
+ rescue ActiveRecord::NoDatabaseError
124
+ warn <<-end_warning
125
+ Oops - You have a database configured, but it doesn't exist yet!
127
126
 
128
- self.configurations = Rails.application.config.database_configuration
129
- establish_connection
127
+ Here's how to get started:
128
+
129
+ 1. Configure your database in config/database.yml.
130
+ 2. Run `bin/rake db:create` to create the database.
131
+ 3. Run `bin/rake db:setup` to load your database schema.
132
+ end_warning
133
+ raise
134
+ end
130
135
  end
131
136
  end
132
137
 
@@ -144,8 +149,8 @@ module ActiveRecord
144
149
  ActiveSupport.on_load(:active_record) do
145
150
  ActionDispatch::Reloader.send(hook) do
146
151
  if ActiveRecord::Base.connected?
147
- ActiveRecord::Base.clear_reloadable_connections!
148
152
  ActiveRecord::Base.clear_cache!
153
+ ActiveRecord::Base.clear_reloadable_connections!
149
154
  end
150
155
  end
151
156
  end
@@ -28,21 +28,32 @@ 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
37
- db_namespace['_dump'].invoke if ActiveRecord::Base.dump_schema_after_migration
44
+ ActiveRecord::Tasks::DatabaseTasks.migrate
45
+ db_namespace['_dump'].invoke
38
46
  end
39
47
 
48
+ # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
40
49
  task :_dump do
41
- case ActiveRecord::Base.schema_format
42
- when :ruby then db_namespace["schema:dump"].invoke
43
- when :sql then db_namespace["structure:dump"].invoke
44
- else
45
- raise "unknown schema format #{ActiveRecord::Base.schema_format}"
50
+ if ActiveRecord::Base.dump_schema_after_migration
51
+ case ActiveRecord::Base.schema_format
52
+ when :ruby then db_namespace["schema:dump"].invoke
53
+ when :sql then db_namespace["structure:dump"].invoke
54
+ else
55
+ raise "unknown schema format #{ActiveRecord::Base.schema_format}"
56
+ end
46
57
  end
47
58
  # Allow this task to be called as many times as required. An example is the
48
59
  # migrate:redo task, which calls other two internally that depend on this one.
@@ -52,6 +63,8 @@ db_namespace = namespace :db do
52
63
  namespace :migrate do
53
64
  # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
54
65
  task :redo => [:environment, :load_config] do
66
+ raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
67
+
55
68
  if ENV['VERSION']
56
69
  db_namespace['migrate:down'].invoke
57
70
  db_namespace['migrate:up'].invoke
@@ -66,48 +79,34 @@ db_namespace = namespace :db do
66
79
 
67
80
  # desc 'Runs the "up" for a given migration VERSION.'
68
81
  task :up => [:environment, :load_config] do
82
+ raise "VERSION is required" if ENV["VERSION"] && ENV["VERSION"].empty?
83
+
69
84
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
70
- raise 'VERSION is required' unless version
71
85
  ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
72
86
  db_namespace['_dump'].invoke
73
87
  end
74
88
 
75
89
  # desc 'Runs the "down" for a given migration VERSION.'
76
90
  task :down => [:environment, :load_config] do
91
+ raise "VERSION is required - To go down one migration, use db:rollback" if ENV["VERSION"] && ENV["VERSION"].empty?
77
92
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
78
- raise 'VERSION is required - To go down one migration, run db:rollback' unless version
79
93
  ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
80
94
  db_namespace['_dump'].invoke
81
95
  end
82
96
 
83
97
  desc 'Display status of migrations'
84
98
  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
88
- end
89
- db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
90
- db_list.map! { |version| ActiveRecord::SchemaMigration.normalize_migration_number(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
- version = ActiveRecord::SchemaMigration.normalize_migration_number(match_data[1])
97
- status = db_list.delete(version) ? 'up' : 'down'
98
- file_list << [status, version, match_data[2].humanize]
99
- end
100
- end
101
- end
102
- db_list.map! do |version|
103
- ['up', version, '********** NO FILE **********']
99
+ unless ActiveRecord::SchemaMigration.table_exists?
100
+ abort 'Schema migrations table does not exist yet.'
104
101
  end
102
+
105
103
  # output
106
104
  puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
107
105
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
108
106
  puts "-" * 50
109
- (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
110
- puts "#{migration[0].center(8)} #{migration[1].ljust(14)} #{migration[2]}"
107
+ paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
108
+ ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
109
+ puts "#{status.center(8)} #{version.ljust(14)} #{name}"
111
110
  end
112
111
  puts
113
112
  end
@@ -179,17 +178,22 @@ db_namespace = namespace :db do
179
178
  task :load => [:environment, :load_config] do
180
179
  require 'active_record/fixtures'
181
180
 
182
- base_dir = if ENV['FIXTURES_PATH']
183
- File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
184
- else
185
- ActiveRecord::Tasks::DatabaseTasks.fixtures_path
186
- end
181
+ base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
187
182
 
188
- fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
183
+ fixtures_dir = if ENV['FIXTURES_DIR']
184
+ File.join base_dir, ENV['FIXTURES_DIR']
185
+ else
186
+ base_dir
187
+ end
189
188
 
190
- (ENV['FIXTURES'] ? ENV['FIXTURES'].split(',') : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
191
- ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_file)
192
- end
189
+ fixture_files = if ENV['FIXTURES']
190
+ ENV['FIXTURES'].split(',')
191
+ else
192
+ # The use of String#[] here is to support namespaced fixtures
193
+ Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
194
+ end
195
+
196
+ ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
193
197
  end
194
198
 
195
199
  # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
@@ -201,16 +205,11 @@ db_namespace = namespace :db do
201
205
 
202
206
  puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
203
207
 
204
- base_dir = if ENV['FIXTURES_PATH']
205
- File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
206
- else
207
- ActiveRecord::Tasks::DatabaseTasks.fixtures_path
208
- end
209
-
208
+ base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
210
209
 
211
210
  Dir["#{base_dir}/**/*.yml"].each do |file|
212
211
  if data = YAML::load(ERB.new(IO.read(file)).result)
213
- data.keys.each do |key|
212
+ data.each_key do |key|
214
213
  key_id = ActiveRecord::FixtureSet.identify(key)
215
214
 
216
215
  if key == label || key_id == id.to_i
@@ -279,8 +278,8 @@ db_namespace = namespace :db do
279
278
  db_namespace['structure:dump'].reenable
280
279
  end
281
280
 
282
- # desc "Recreate the databases from the structure.sql file"
283
- task :load => [:environment, :load_config] do
281
+ desc "Recreate the databases from the structure.sql file"
282
+ task :load => [:load_config] do
284
283
  ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
285
284
  end
286
285
 
@@ -299,7 +298,7 @@ db_namespace = namespace :db do
299
298
  end
300
299
 
301
300
  # desc "Recreate the test database from the current schema"
302
- task :load => %w(db:test:deprecated db:test:purge) do
301
+ task :load => %w(db:test:purge) do
303
302
  case ActiveRecord::Base.schema_format
304
303
  when :ruby
305
304
  db_namespace["test:load_schema"].invoke
@@ -309,7 +308,7 @@ db_namespace = namespace :db do
309
308
  end
310
309
 
311
310
  # desc "Recreate the test database from an existent schema.rb file"
312
- task :load_schema => %w(db:test:deprecated db:test:purge) do
311
+ task :load_schema => %w(db:test:purge) do
313
312
  begin
314
313
  should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
315
314
  ActiveRecord::Schema.verbose = false
@@ -322,7 +321,7 @@ db_namespace = namespace :db do
322
321
  end
323
322
 
324
323
  # desc "Recreate the test database from an existent structure.sql file"
325
- task :load_structure => %w(db:test:deprecated db:test:purge) do
324
+ task :load_structure => %w(db:test:purge) do
326
325
  ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
327
326
  end
328
327
 
@@ -343,12 +342,12 @@ db_namespace = namespace :db do
343
342
  task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure)
344
343
 
345
344
  # desc "Empty the test database"
346
- task :purge => %w(db:test:deprecated environment load_config) do
345
+ task :purge => %w(environment load_config) do
347
346
  ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
348
347
  end
349
348
 
350
349
  # desc 'Check for pending migrations and load the test schema'
351
- task :prepare => %w(db:test:deprecated environment load_config) do
350
+ task :prepare => %w(environment load_config) do
352
351
  unless ActiveRecord::Base.configurations.blank?
353
352
  db_namespace['test:load'].invoke
354
353
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module ActiveRecord
3
2
  module ReadonlyAttributes
4
3
  extend ActiveSupport::Concern