activerecord 4.0.13 → 4.1.0.beta1

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

Potentially problematic release.


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

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -32,6 +32,12 @@ module ActiveRecord
32
32
  class_attribute :table_name_suffix, instance_writer: false
33
33
  self.table_name_suffix = ""
34
34
 
35
+ ##
36
+ # :singleton-method:
37
+ # Accessor for the name of the schema migrations table. By default, the value is "schema_migrations"
38
+ class_attribute :schema_migrations_table_name, instance_accessor: false
39
+ self.schema_migrations_table_name = "schema_migrations"
40
+
35
41
  ##
36
42
  # :singleton-method:
37
43
  # Indicates whether table names should be the pluralized versions of the corresponding class names.
@@ -124,7 +130,7 @@ module ActiveRecord
124
130
  @quoted_table_name = nil
125
131
  @arel_table = nil
126
132
  @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
127
- @relation = Relation.new(self, arel_table)
133
+ @relation = Relation.create(self, arel_table)
128
134
  end
129
135
 
130
136
  # Returns a quoted version of the table name, used to construct SQL statements.
@@ -260,19 +266,6 @@ module ActiveRecord
260
266
  @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
261
267
  end
262
268
 
263
- # Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
264
- # and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
265
- # is available.
266
- def column_methods_hash #:nodoc:
267
- @dynamic_methods_hash ||= column_names.each_with_object(Hash.new(false)) do |attr, methods|
268
- attr_name = attr.to_s
269
- methods[attr.to_sym] = attr_name
270
- methods["#{attr}=".to_sym] = attr_name
271
- methods["#{attr}?".to_sym] = attr_name
272
- methods["#{attr}_before_type_cast".to_sym] = attr_name
273
- end
274
- end
275
-
276
269
  # Resets all the cached information about columns, which will cause them
277
270
  # to be reloaded on the next request.
278
271
  #
@@ -230,6 +230,10 @@ module ActiveRecord
230
230
  # validates_presence_of :member
231
231
  # end
232
232
  #
233
+ # Note that if you do not specify the <tt>inverse_of</tt> option, then
234
+ # Active Record will try to automatically guess the inverse association
235
+ # based on heuristics.
236
+ #
233
237
  # For one-to-one nested associations, if you build the new (in-memory)
234
238
  # child object yourself before assignment, then this module will not
235
239
  # overwrite it, e.g.:
@@ -302,7 +306,7 @@ module ActiveRecord
302
306
 
303
307
  attr_names.each do |association_name|
304
308
  if reflection = reflect_on_association(association_name)
305
- reflection.options[:autosave] = true
309
+ reflection.autosave = true
306
310
  add_autosave_association_callbacks(reflection)
307
311
 
308
312
  nested_attributes_options = self.nested_attributes_options.dup
@@ -331,7 +335,7 @@ module ActiveRecord
331
335
  # the helper methods defined below. Makes it seem like the nested
332
336
  # associations are just regular associations.
333
337
  def generate_association_writer(association_name, type)
334
- generated_feature_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
338
+ generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
335
339
  if method_defined?(:#{association_name}_attributes=)
336
340
  remove_method(:#{association_name}_attributes=)
337
341
  end
@@ -461,19 +465,17 @@ module ActiveRecord
461
465
  association.build(attributes.except(*UNASSIGNABLE_KEYS))
462
466
  end
463
467
  elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
464
- unless association.loaded? || call_reject_if(association_name, attributes)
468
+ unless call_reject_if(association_name, attributes)
465
469
  # Make sure we are operating on the actual object which is in the association's
466
470
  # proxy_target array (either by finding it, or adding it if not found)
467
- target_record = association.target.detect { |record| record == existing_record }
468
-
471
+ # Take into account that the proxy_target may have changed due to callbacks
472
+ target_record = association.target.detect { |record| record.id.to_s == attributes['id'].to_s }
469
473
  if target_record
470
474
  existing_record = target_record
471
475
  else
472
- association.add_to_target(existing_record)
476
+ association.add_to_target(existing_record, :skip_callbacks)
473
477
  end
474
- end
475
478
 
476
- if !call_reject_if(association_name, attributes)
477
479
  assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
478
480
  end
479
481
  else
@@ -0,0 +1,52 @@
1
+ module ActiveRecord
2
+ # = Active Record No Touching
3
+ module NoTouching
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ # Lets you selectively disable calls to `touch` for the
8
+ # duration of a block.
9
+ #
10
+ # ==== Examples
11
+ # ActiveRecord::Base.no_touching do
12
+ # Project.first.touch # does nothing
13
+ # Message.first.touch # does nothing
14
+ # end
15
+ #
16
+ # Project.no_touching do
17
+ # Project.first.touch # does nothing
18
+ # Message.first.touch # works, but does not touch the associated project
19
+ # end
20
+ #
21
+ def no_touching(&block)
22
+ NoTouching.apply_to(self, &block)
23
+ end
24
+ end
25
+
26
+ class << self
27
+ def apply_to(klass) #:nodoc:
28
+ klasses.push(klass)
29
+ yield
30
+ ensure
31
+ klasses.pop
32
+ end
33
+
34
+ def applied_to?(klass) #:nodoc:
35
+ klasses.any? { |k| k >= klass }
36
+ end
37
+
38
+ private
39
+ def klasses
40
+ Thread.current[:no_touching_classes] ||= []
41
+ end
42
+ end
43
+
44
+ def no_touching?
45
+ NoTouching.applied_to?(self.class)
46
+ end
47
+
48
+ def touch(*)
49
+ super unless no_touching?
50
+ end
51
+ end
52
+ end
@@ -39,11 +39,11 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  def to_sql
42
- @to_sql ||= ""
42
+ ""
43
43
  end
44
44
 
45
45
  def count(*)
46
- calculate :count, nil
46
+ 0
47
47
  end
48
48
 
49
49
  def sum(*)
@@ -54,7 +54,7 @@ module ActiveRecord
54
54
  # TODO: Remove _options argument as soon we remove support to
55
55
  # activerecord-deprecated_finders.
56
56
  if operation == :count
57
- group_values.any? ? Hash.new : 0
57
+ 0
58
58
  else
59
59
  nil
60
60
  end
@@ -37,7 +37,7 @@ module ActiveRecord
37
37
  end
38
38
 
39
39
  # Given an attributes hash, +instantiate+ returns a new instance of
40
- # the appropriate class. Accepts only keys as strings.
40
+ # the appropriate class.
41
41
  #
42
42
  # For example, +Post.all+ may return Comments, Messages, and Emails
43
43
  # by storing the record's subclass in a +type+ attribute. By calling
@@ -46,10 +46,10 @@ module ActiveRecord
46
46
  #
47
47
  # See +ActiveRecord::Inheritance#discriminate_class_for_record+ to see
48
48
  # how this "single-table" inheritance mapping is implemented.
49
- def instantiate(attributes, column_types = {})
50
- klass = discriminate_class_for_record(attributes)
49
+ def instantiate(record, column_types = {})
50
+ klass = discriminate_class_for_record(record)
51
51
  column_types = klass.decorate_columns(column_types.dup)
52
- klass.allocate.init_with('attributes' => attributes, 'column_types' => column_types)
52
+ klass.allocate.init_with('attributes' => record, 'column_types' => column_types)
53
53
  end
54
54
 
55
55
  private
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  end
65
65
 
66
66
  # Returns true if this object hasn't been saved yet -- that is, a record
67
- # for the object doesn't exist in the database yet; otherwise, returns false.
67
+ # for the object doesn't exist in the data store yet; otherwise, returns false.
68
68
  def new_record?
69
69
  sync_with_transaction_state
70
70
  @new_record
@@ -195,11 +195,7 @@ module ActiveRecord
195
195
  # share the same set of attributes.
196
196
  def becomes!(klass)
197
197
  became = becomes(klass)
198
- sti_type = nil
199
- if !klass.descends_from_active_record?
200
- sti_type = klass.sti_name
201
- end
202
- became.public_send("#{klass.inheritance_column}=", sti_type)
198
+ became.public_send("#{klass.inheritance_column}=", klass.sti_name) unless self.class.descends_from_active_record?
203
199
  became
204
200
  end
205
201
 
@@ -346,7 +342,8 @@ module ActiveRecord
346
342
  # # Account Load (1.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1 [["id", 1]]
347
343
  # # => #<Account id: 1, email: 'account@example.com'>
348
344
  #
349
- # Attributes are updated, and caches busted, in particular the associations cache.
345
+ # Attributes are reloaded from the database, and caches busted, in
346
+ # particular the associations cache.
350
347
  #
351
348
  # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
352
349
  # is raised. Otherwise, in addition to the in-place modification the method
@@ -387,7 +384,7 @@ module ActiveRecord
387
384
 
388
385
  fresh_object =
389
386
  if options && options[:lock]
390
- self.class.unscoped { self.class.lock(options[:lock]).find(id) }
387
+ self.class.unscoped { self.class.lock.find(id) }
391
388
  else
392
389
  self.class.unscoped { self.class.find(id) }
393
390
  end
@@ -397,7 +394,6 @@ module ActiveRecord
397
394
  @column_types = self.class.column_types
398
395
  @column_types_override = fresh_object.instance_variable_get('@column_types_override')
399
396
  @attributes_cache = {}
400
- @new_record = false
401
397
  self
402
398
  end
403
399
 
@@ -446,11 +442,9 @@ module ActiveRecord
446
442
 
447
443
  changes[self.class.locking_column] = increment_lock if locking_enabled?
448
444
 
449
- @changed_attributes.except!(*changes.keys)
445
+ changed_attributes.except!(*changes.keys)
450
446
  primary_key = self.class.primary_key
451
447
  self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
452
- else
453
- true
454
448
  end
455
449
  end
456
450
 
@@ -478,36 +472,24 @@ module ActiveRecord
478
472
 
479
473
  def create_or_update
480
474
  raise ReadOnlyRecord if readonly?
481
- result = new_record? ? _create_record : _update_record
475
+ result = new_record? ? create_record : update_record
482
476
  result != false
483
477
  end
484
478
 
485
479
  # Updates the associated record with values matching those of the instance attributes.
486
480
  # Returns the number of affected rows.
487
- def _update_record(attribute_names = @attributes.keys)
488
- attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
489
- if attributes_with_values.empty?
481
+ def update_record(attribute_names = @attributes.keys)
482
+ attributes_values = arel_attributes_with_values_for_update(attribute_names)
483
+ if attributes_values.empty?
490
484
  0
491
485
  else
492
- klass = self.class
493
- column_hash = klass.connection.schema_cache.columns_hash klass.table_name
494
- db_columns_with_values = attributes_with_values.map { |attr,value|
495
- real_column = column_hash[attr.name]
496
- [real_column, value]
497
- }
498
- bind_attrs = attributes_with_values.dup
499
- bind_attrs.keys.each_with_index do |column, i|
500
- real_column = db_columns_with_values[i].first
501
- bind_attrs[column] = klass.connection.substitute_at(real_column, i)
502
- end
503
- stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id)).arel.compile_update(bind_attrs)
504
- klass.connection.update stmt, 'SQL', db_columns_with_values
486
+ self.class.unscoped.update_record attributes_values, id, id_was
505
487
  end
506
488
  end
507
489
 
508
490
  # Creates a record with values matching those of the instance attributes
509
491
  # and returns its id.
510
- def _create_record(attribute_names = @attributes.keys)
492
+ def create_record(attribute_names = @attributes.keys)
511
493
  attributes_values = arel_attributes_with_values_for_create(attribute_names)
512
494
 
513
495
  new_id = self.class.unscoped.insert attributes_values
@@ -1,20 +1,21 @@
1
1
  module ActiveRecord
2
2
  module Querying
3
- delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :to => :all
4
- delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :all
5
- delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :to => :all
6
- delegate :find_by, :find_by!, :to => :all
7
- delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :all
8
- delegate :find_each, :find_in_batches, :to => :all
3
+ delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, to: :all
4
+ delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
5
+ delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
6
+ delegate :find_by, :find_by!, to: :all
7
+ delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all
8
+ delegate :find_each, :find_in_batches, to: :all
9
9
  delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
10
- :where, :preload, :eager_load, :includes, :from, :lock, :readonly,
11
- :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :all
12
- delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :all
10
+ :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
11
+ :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all
12
+ delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
13
+ delegate :pluck, :ids, to: :all
13
14
 
14
15
  # Executes a custom SQL query against your database and returns all the results. The results will
15
16
  # be returned as an array with columns requested encapsulated as attributes of the model you call
16
17
  # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
17
- # a Product object with the attributes you specified in the SQL query.
18
+ # a +Product+ object with the attributes you specified in the SQL query.
18
19
  #
19
20
  # If you call a complicated SQL query which spans multiple tables the columns specified by the
20
21
  # SELECT will be attributes of the model, whether or not they are columns of the corresponding
@@ -29,9 +30,10 @@ module ActiveRecord
29
30
  # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
30
31
  # # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
31
32
  #
32
- # # You can use the same string replacement techniques as you can with ActiveRecord#find
33
+ # You can use the same string replacement techniques as you can with <tt>ActiveRecord::QueryMethods#where</tt>:
34
+ #
33
35
  # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
34
- # # => [#<Post:0x36bff9c @attributes={"title"=>"The Cheap Man Buys Twice"}>, ...]
36
+ # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
35
37
  def find_by_sql(sql, binds = [])
36
38
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds)
37
39
  column_types = {}
@@ -112,56 +112,6 @@ module ActiveRecord
112
112
 
113
113
  initializer "active_record.set_configs" do |app|
114
114
  ActiveSupport.on_load(:active_record) do
115
- begin
116
- old_behavior, ActiveSupport::Deprecation.behavior = ActiveSupport::Deprecation.behavior, :stderr
117
- whitelist_attributes = app.config.active_record.delete(:whitelist_attributes)
118
-
119
- if respond_to?(:mass_assignment_sanitizer=)
120
- mass_assignment_sanitizer = nil
121
- else
122
- mass_assignment_sanitizer = app.config.active_record.delete(:mass_assignment_sanitizer)
123
- end
124
-
125
- unless whitelist_attributes.nil? && mass_assignment_sanitizer.nil?
126
- ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
127
- Model based mass assignment security has been extracted
128
- out of Rails into a gem. Please use the new recommended protection model for
129
- params or add `protected_attributes` to your Gemfile to use the old one.
130
-
131
- To disable this message remove the `whitelist_attributes` option from your
132
- `config/application.rb` file and any `mass_assignment_sanitizer` options
133
- from your `config/environments/*.rb` files.
134
-
135
- See http://guides.rubyonrails.org/security.html#mass-assignment for more information.
136
- EOF
137
- end
138
-
139
- unless app.config.active_record.delete(:auto_explain_threshold_in_seconds).nil?
140
- ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
141
- The Active Record auto explain feature has been removed.
142
-
143
- To disable this message remove the `active_record.auto_explain_threshold_in_seconds`
144
- option from the `config/environments/*.rb` config file.
145
-
146
- See http://guides.rubyonrails.org/4_0_release_notes.html for more information.
147
- EOF
148
- end
149
-
150
- unless app.config.active_record.delete(:observers).nil?
151
- ActiveSupport::Deprecation.warn <<-EOF.strip_heredoc, []
152
- Active Record Observers has been extracted out of Rails into a gem.
153
- Please use callbacks or add `rails-observers` to your Gemfile to use observers.
154
-
155
- To disable this message remove the `observers` option from your
156
- `config/application.rb` or from your initializers.
157
-
158
- See http://guides.rubyonrails.org/4_0_release_notes.html for more information.
159
- EOF
160
- end
161
- ensure
162
- ActiveSupport::Deprecation.behavior = old_behavior
163
- end
164
-
165
115
  app.config.active_record.each do |k,v|
166
116
  send "#{k}=", v
167
117
  end
@@ -12,7 +12,7 @@ db_namespace = namespace :db do
12
12
  end
13
13
  end
14
14
 
15
- desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
15
+ desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)'
16
16
  task :create => [:load_config] do
17
17
  if ENV['DATABASE_URL']
18
18
  ActiveRecord::Tasks::DatabaseTasks.create_database_url
@@ -95,15 +95,14 @@ db_namespace = namespace :db do
95
95
  next # means "return" for rake task
96
96
  end
97
97
  db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
98
- db_list.map! { |version| ActiveRecord::SchemaMigration.normalize_migration_number(version) }
98
+ db_list.map! { |version| "%.3d" % version }
99
99
  file_list = []
100
100
  ActiveRecord::Migrator.migrations_paths.each do |path|
101
101
  Dir.foreach(path) do |file|
102
102
  # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
103
103
  if match_data = /^(\d{3,})_(.+)\.rb$/.match(file)
104
- version = ActiveRecord::SchemaMigration.normalize_migration_number(match_data[1])
105
- status = db_list.delete(version) ? 'up' : 'down'
106
- file_list << [status, version, match_data[2].humanize]
104
+ status = db_list.delete(match_data[1]) ? 'up' : 'down'
105
+ file_list << [status, match_data[1], match_data[2].humanize]
107
106
  end
108
107
  end
109
108
  end
@@ -173,7 +172,7 @@ db_namespace = namespace :db do
173
172
  end
174
173
  end
175
174
 
176
- desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
175
+ desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)'
177
176
  task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
178
177
 
179
178
  desc 'Load the seed data from db/seeds.rb'
@@ -237,7 +236,7 @@ db_namespace = namespace :db do
237
236
  end
238
237
 
239
238
  namespace :schema do
240
- desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
239
+ desc 'Create a db/schema.rb file that is portable against any DB supported by AR'
241
240
  task :dump => [:environment, :load_config] do
242
241
  require 'active_record/schema_dumper'
243
242
  filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
@@ -250,11 +249,8 @@ db_namespace = namespace :db do
250
249
  desc 'Load a schema.rb file into the database'
251
250
  task :load => [:environment, :load_config] do
252
251
  file = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
253
- if File.exist?(file)
254
- load(file)
255
- else
256
- abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.}
257
- end
252
+ ActiveRecord::Tasks::DatabaseTasks.check_schema_file(file)
253
+ load(file)
258
254
  end
259
255
 
260
256
  task :load_if_ruby => ['db:create', :environment] do
@@ -288,10 +284,10 @@ db_namespace = namespace :db do
288
284
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
289
285
  ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
290
286
 
291
- if ActiveRecord::Base.connection.supports_migrations? &&
292
- ActiveRecord::SchemaMigration.table_exists?
287
+ if ActiveRecord::Base.connection.supports_migrations?
293
288
  File.open(filename, "a") do |f|
294
289
  f.puts ActiveRecord::Base.connection.dump_schema_information
290
+ f.print "\n"
295
291
  end
296
292
  end
297
293
  db_namespace['structure:dump'].reenable
@@ -300,6 +296,7 @@ db_namespace = namespace :db do
300
296
  # desc "Recreate the databases from the structure.sql file"
301
297
  task :load => [:environment, :load_config] do
302
298
  filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
299
+ ActiveRecord::Tasks::DatabaseTasks.check_schema_file(filename)
303
300
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
304
301
  ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
305
302
  end
@@ -381,7 +378,7 @@ namespace :railties do
381
378
  task :migrations => :'db:load_config' do
382
379
  to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
383
380
  railties = {}
384
- Rails.application.migration_railties.each do |railtie|
381
+ Rails.application.railties.each do |railtie|
385
382
  next unless to_load == :all || to_load.include?(railtie.railtie_name)
386
383
 
387
384
  if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)