activerecord 3.1.12 → 3.2.22.1

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +804 -338
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +20 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +3 -6
  7. data/lib/active_record/associations/association.rb +13 -45
  8. data/lib/active_record/associations/association_scope.rb +3 -15
  9. data/lib/active_record/associations/belongs_to_association.rb +1 -1
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +2 -1
  11. data/lib/active_record/associations/builder/association.rb +6 -4
  12. data/lib/active_record/associations/builder/belongs_to.rb +7 -4
  13. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  14. data/lib/active_record/associations/builder/has_many.rb +4 -4
  15. data/lib/active_record/associations/builder/has_one.rb +5 -6
  16. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  17. data/lib/active_record/associations/collection_association.rb +65 -32
  18. data/lib/active_record/associations/collection_proxy.rb +8 -41
  19. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
  20. data/lib/active_record/associations/has_many_association.rb +11 -7
  21. data/lib/active_record/associations/has_many_through_association.rb +19 -9
  22. data/lib/active_record/associations/has_one_association.rb +23 -13
  23. data/lib/active_record/associations/join_dependency/join_association.rb +6 -1
  24. data/lib/active_record/associations/join_dependency.rb +3 -3
  25. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  26. data/lib/active_record/associations/preloader.rb +14 -10
  27. data/lib/active_record/associations/through_association.rb +8 -4
  28. data/lib/active_record/associations.rb +92 -76
  29. data/lib/active_record/attribute_assignment.rb +221 -0
  30. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  31. data/lib/active_record/attribute_methods/dirty.rb +21 -11
  32. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  33. data/lib/active_record/attribute_methods/read.rb +73 -83
  34. data/lib/active_record/attribute_methods/serialization.rb +120 -0
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  36. data/lib/active_record/attribute_methods/write.rb +32 -6
  37. data/lib/active_record/attribute_methods.rb +231 -30
  38. data/lib/active_record/autosave_association.rb +44 -26
  39. data/lib/active_record/base.rb +227 -1708
  40. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +150 -148
  41. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +85 -29
  42. data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -34
  43. data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -4
  45. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +39 -28
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -19
  47. data/lib/active_record/connection_adapters/abstract_adapter.rb +77 -42
  48. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
  49. data/lib/active_record/connection_adapters/column.rb +37 -11
  50. data/lib/active_record/connection_adapters/mysql2_adapter.rb +133 -581
  51. data/lib/active_record/connection_adapters/mysql_adapter.rb +136 -693
  52. data/lib/active_record/connection_adapters/postgresql_adapter.rb +209 -97
  53. data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
  54. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  55. data/lib/active_record/connection_adapters/sqlite_adapter.rb +62 -35
  56. data/lib/active_record/counter_cache.rb +9 -4
  57. data/lib/active_record/dynamic_finder_match.rb +12 -0
  58. data/lib/active_record/dynamic_matchers.rb +84 -0
  59. data/lib/active_record/errors.rb +11 -1
  60. data/lib/active_record/explain.rb +86 -0
  61. data/lib/active_record/explain_subscriber.rb +25 -0
  62. data/lib/active_record/fixtures/file.rb +65 -0
  63. data/lib/active_record/fixtures.rb +57 -86
  64. data/lib/active_record/identity_map.rb +3 -4
  65. data/lib/active_record/inheritance.rb +174 -0
  66. data/lib/active_record/integration.rb +60 -0
  67. data/lib/active_record/locking/optimistic.rb +33 -26
  68. data/lib/active_record/locking/pessimistic.rb +23 -1
  69. data/lib/active_record/log_subscriber.rb +8 -4
  70. data/lib/active_record/migration/command_recorder.rb +8 -8
  71. data/lib/active_record/migration.rb +68 -35
  72. data/lib/active_record/model_schema.rb +368 -0
  73. data/lib/active_record/nested_attributes.rb +60 -24
  74. data/lib/active_record/persistence.rb +57 -11
  75. data/lib/active_record/query_cache.rb +6 -6
  76. data/lib/active_record/querying.rb +58 -0
  77. data/lib/active_record/railtie.rb +37 -29
  78. data/lib/active_record/railties/controller_runtime.rb +3 -1
  79. data/lib/active_record/railties/databases.rake +213 -117
  80. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  81. data/lib/active_record/readonly_attributes.rb +26 -0
  82. data/lib/active_record/reflection.rb +7 -15
  83. data/lib/active_record/relation/batches.rb +7 -4
  84. data/lib/active_record/relation/calculations.rb +55 -16
  85. data/lib/active_record/relation/delegation.rb +49 -0
  86. data/lib/active_record/relation/finder_methods.rb +16 -11
  87. data/lib/active_record/relation/predicate_builder.rb +8 -6
  88. data/lib/active_record/relation/query_methods.rb +75 -9
  89. data/lib/active_record/relation/spawn_methods.rb +48 -7
  90. data/lib/active_record/relation.rb +78 -32
  91. data/lib/active_record/result.rb +10 -4
  92. data/lib/active_record/sanitization.rb +194 -0
  93. data/lib/active_record/schema_dumper.rb +12 -5
  94. data/lib/active_record/scoping/default.rb +142 -0
  95. data/lib/active_record/scoping/named.rb +200 -0
  96. data/lib/active_record/scoping.rb +152 -0
  97. data/lib/active_record/serialization.rb +1 -43
  98. data/lib/active_record/serializers/xml_serializer.rb +4 -45
  99. data/lib/active_record/session_store.rb +18 -16
  100. data/lib/active_record/store.rb +52 -0
  101. data/lib/active_record/test_case.rb +11 -7
  102. data/lib/active_record/timestamp.rb +17 -3
  103. data/lib/active_record/transactions.rb +27 -6
  104. data/lib/active_record/translation.rb +22 -0
  105. data/lib/active_record/validations/associated.rb +5 -4
  106. data/lib/active_record/validations/uniqueness.rb +8 -8
  107. data/lib/active_record/validations.rb +1 -1
  108. data/lib/active_record/version.rb +3 -3
  109. data/lib/active_record.rb +38 -3
  110. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  111. data/lib/rails/generators/active_record/migration/templates/migration.rb +12 -3
  112. data/lib/rails/generators/active_record/model/model_generator.rb +9 -1
  113. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  114. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  115. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  116. metadata +49 -28
  117. data/lib/active_record/named_scope.rb +0 -200
@@ -26,13 +26,17 @@ module ActiveRecord
26
26
 
27
27
  return if 'SCHEMA' == payload[:name]
28
28
 
29
- name = '%s (%.1fms)' % [payload[:name], event.duration]
30
- sql = payload[:sql].squeeze(' ')
31
- binds = nil
29
+ name = '%s (%.1fms)' % [payload[:name], event.duration]
30
+ sql = payload[:sql].squeeze(' ')
31
+ binds = nil
32
32
 
33
33
  unless (payload[:binds] || []).empty?
34
34
  binds = " " + payload[:binds].map { |col,v|
35
- [col.name, v]
35
+ if col
36
+ [col.name, v]
37
+ else
38
+ [nil, v]
39
+ end
36
40
  }.inspect
37
41
  end
38
42
 
@@ -1,12 +1,12 @@
1
1
  module ActiveRecord
2
2
  class Migration
3
- # ActiveRecord::Migration::CommandRecorder records commands done during
4
- # a migration and knows how to reverse those commands. The CommandRecorder
3
+ # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
4
+ # a migration and knows how to reverse those commands. The CommandRecorder
5
5
  # knows how to invert the following commands:
6
6
  #
7
7
  # * add_column
8
8
  # * add_index
9
- # * add_timestamp
9
+ # * add_timestamps
10
10
  # * create_table
11
11
  # * remove_timestamps
12
12
  # * rename_column
@@ -20,21 +20,21 @@ module ActiveRecord
20
20
  @delegate = delegate
21
21
  end
22
22
 
23
- # record +command+. +command+ should be a method name and arguments.
23
+ # record +command+. +command+ should be a method name and arguments.
24
24
  # For example:
25
25
  #
26
- # recorder.record(:method_name, [:arg1, arg2])
26
+ # recorder.record(:method_name, [:arg1, :arg2])
27
27
  def record(*command)
28
28
  @commands << command
29
29
  end
30
30
 
31
31
  # Returns a list that represents commands that are the inverse of the
32
- # commands stored in +commands+. For example:
32
+ # commands stored in +commands+. For example:
33
33
  #
34
34
  # recorder.record(:rename_table, [:old, :new])
35
35
  # recorder.inverse # => [:rename_table, [:new, :old]]
36
36
  #
37
- # This method will raise an IrreversibleMigration exception if it cannot
37
+ # This method will raise an +IrreversibleMigration+ exception if it cannot
38
38
  # invert the +commands+.
39
39
  def inverse
40
40
  @commands.reverse.map { |name, args|
@@ -59,7 +59,7 @@ module ActiveRecord
59
59
  private
60
60
 
61
61
  def invert_create_table(args)
62
- [:drop_table, args]
62
+ [:drop_table, [args.first]]
63
63
  end
64
64
 
65
65
  def invert_rename_table(args)
@@ -1,6 +1,7 @@
1
1
  require "active_support/core_ext/module/delegation"
2
2
  require "active_support/core_ext/class/attribute_accessors"
3
3
  require "active_support/core_ext/array/wrap"
4
+ require 'active_support/deprecation'
4
5
 
5
6
  module ActiveRecord
6
7
  # Exception that can be raised to stop migrations from going backwards.
@@ -68,9 +69,9 @@ module ActiveRecord
68
69
  # create_table :system_settings do |t|
69
70
  # t.string :name
70
71
  # t.string :label
71
- # t.text :value
72
+ # t.text :value
72
73
  # t.string :type
73
- # t.integer :position
74
+ # t.integer :position
74
75
  # end
75
76
  #
76
77
  # SystemSetting.create :name => "notice",
@@ -116,8 +117,9 @@ module ActiveRecord
116
117
  # +column_names+ from the table called +table_name+.
117
118
  # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
118
119
  # with the name of the column. Other options include
119
- # <tt>:name</tt> and <tt>:unique</tt> (e.g.
120
- # <tt>{ :name => "users_name_index", :unique => true }</tt>).
120
+ # <tt>:name</tt>, <tt>:unique</tt> (e.g.
121
+ # <tt>{ :name => "users_name_index", :unique => true }</tt>) and <tt>:order</tt>
122
+ # (e.g. { :order => {:name => :desc} }</tt>).
121
123
  # * <tt>remove_index(table_name, :column => column_name)</tt>: Removes the index
122
124
  # specified by +column_name+.
123
125
  # * <tt>remove_index(table_name, :name => index_name)</tt>: Removes the index
@@ -183,7 +185,7 @@ module ActiveRecord
183
185
  #
184
186
  # class RemoveEmptyTags < ActiveRecord::Migration
185
187
  # def up
186
- # Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
188
+ # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
187
189
  # end
188
190
  #
189
191
  # def down
@@ -229,7 +231,7 @@ module ActiveRecord
229
231
  # def up
230
232
  # add_column :people, :salary, :integer
231
233
  # Person.reset_column_information
232
- # Person.find(:all).each do |p|
234
+ # Person.all.each do |p|
233
235
  # p.update_attribute :salary, SalaryCalculator.compute(p)
234
236
  # end
235
237
  # end
@@ -249,7 +251,7 @@ module ActiveRecord
249
251
  # def up
250
252
  # ...
251
253
  # say_with_time "Updating salaries..." do
252
- # Person.find(:all).each do |p|
254
+ # Person.all.each do |p|
253
255
  # p.update_attribute :salary, SalaryCalculator.compute(p)
254
256
  # end
255
257
  # end
@@ -301,7 +303,7 @@ module ActiveRecord
301
303
  #
302
304
  # class TenderloveMigration < ActiveRecord::Migration
303
305
  # def change
304
- # create_table(:horses) do
306
+ # create_table(:horses) do |t|
305
307
  # t.column :content, :text
306
308
  # t.column :remind_at, :datetime
307
309
  # end
@@ -344,12 +346,24 @@ module ActiveRecord
344
346
  @name = self.class.name
345
347
  @version = nil
346
348
  @connection = nil
349
+ @reverting = false
347
350
  end
348
351
 
349
352
  # instantiate the delegate object after initialize is defined
350
353
  self.verbose = true
351
354
  self.delegate = new
352
355
 
356
+ def revert
357
+ @reverting = true
358
+ yield
359
+ ensure
360
+ @reverting = false
361
+ end
362
+
363
+ def reverting?
364
+ @reverting
365
+ end
366
+
353
367
  def up
354
368
  self.class.delegate = self
355
369
  return unless self.class.respond_to?(:up)
@@ -383,9 +397,11 @@ module ActiveRecord
383
397
  end
384
398
  @connection = conn
385
399
  time = Benchmark.measure {
386
- recorder.inverse.each do |cmd, args|
387
- send(cmd, *args)
388
- end
400
+ self.revert {
401
+ recorder.inverse.each do |cmd, args|
402
+ send(cmd, *args)
403
+ end
404
+ }
389
405
  }
390
406
  else
391
407
  time = Benchmark.measure { change }
@@ -440,8 +456,11 @@ module ActiveRecord
440
456
  arg_list = arguments.map{ |a| a.inspect } * ', '
441
457
 
442
458
  say_with_time "#{method}(#{arg_list})" do
443
- unless arguments.empty? || method == :execute
444
- arguments[0] = Migrator.proper_table_name(arguments.first)
459
+ unless reverting?
460
+ unless arguments.empty? || method == :execute
461
+ arguments[0] = Migrator.proper_table_name(arguments.first) unless method == :assume_migrated_upto_version
462
+ arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
463
+ end
445
464
  end
446
465
  return super unless connection.respond_to?(method)
447
466
  connection.send(method, *arguments, &block)
@@ -455,26 +474,28 @@ module ActiveRecord
455
474
 
456
475
  destination_migrations = ActiveRecord::Migrator.migrations(destination)
457
476
  last = destination_migrations.last
458
- sources.each do |name, path|
477
+ sources.each do |scope, path|
459
478
  source_migrations = ActiveRecord::Migrator.migrations(path)
460
479
 
461
480
  source_migrations.each do |migration|
462
481
  source = File.read(migration.filename)
463
- source = "# This migration comes from #{name} (originally #{migration.version})\n#{source}"
482
+ source = "# This migration comes from #{scope} (originally #{migration.version})\n#{source}"
464
483
 
465
484
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
466
- options[:on_skip].call(name, migration) if File.read(duplicate.filename) != source && options[:on_skip]
485
+ if options[:on_skip] && duplicate.scope != scope.to_s
486
+ options[:on_skip].call(scope, migration)
487
+ end
467
488
  next
468
489
  end
469
490
 
470
491
  migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
471
- new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.rb")
492
+ new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
472
493
  old_path, migration.filename = migration.filename, new_path
473
494
  last = migration
474
495
 
475
- FileUtils.cp(old_path, migration.filename)
496
+ File.open(migration.filename, "w") { |f| f.write source }
476
497
  copied << migration
477
- options[:on_copy].call(name, migration, old_path) if options[:on_copy]
498
+ options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
478
499
  destination_migrations << migration
479
500
  end
480
501
  end
@@ -493,9 +514,9 @@ module ActiveRecord
493
514
 
494
515
  # MigrationProxy is used to defer loading of the actual migration classes
495
516
  # until they are needed
496
- class MigrationProxy < Struct.new(:name, :version, :filename)
517
+ class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
497
518
 
498
- def initialize(name, version, filename)
519
+ def initialize(name, version, filename, scope)
499
520
  super
500
521
  @migration = nil
501
522
  end
@@ -504,7 +525,7 @@ module ActiveRecord
504
525
  File.basename(filename)
505
526
  end
506
527
 
507
- delegate :migrate, :announce, :write, :to=>:migration
528
+ delegate :migrate, :announce, :write, :to => :migration
508
529
 
509
530
  private
510
531
 
@@ -524,16 +545,16 @@ module ActiveRecord
524
545
  attr_writer :migrations_paths
525
546
  alias :migrations_path= :migrations_paths=
526
547
 
527
- def migrate(migrations_paths, target_version = nil)
548
+ def migrate(migrations_paths, target_version = nil, &block)
528
549
  case
529
550
  when target_version.nil?
530
- up(migrations_paths, target_version)
551
+ up(migrations_paths, target_version, &block)
531
552
  when current_version == 0 && target_version == 0
532
553
  []
533
554
  when current_version > target_version
534
- down(migrations_paths, target_version)
555
+ down(migrations_paths, target_version, &block)
535
556
  else
536
- up(migrations_paths, target_version)
557
+ up(migrations_paths, target_version, &block)
537
558
  end
538
559
  end
539
560
 
@@ -545,12 +566,12 @@ module ActiveRecord
545
566
  move(:up, migrations_paths, steps)
546
567
  end
547
568
 
548
- def up(migrations_paths, target_version = nil)
549
- self.new(:up, migrations_paths, target_version).migrate
569
+ def up(migrations_paths, target_version = nil, &block)
570
+ self.new(:up, migrations_paths, target_version).migrate(&block)
550
571
  end
551
572
 
552
- def down(migrations_paths, target_version = nil)
553
- self.new(:down, migrations_paths, target_version).migrate
573
+ def down(migrations_paths, target_version = nil, &block)
574
+ self.new(:down, migrations_paths, target_version).migrate(&block)
554
575
  end
555
576
 
556
577
  def run(direction, migrations_paths, target_version)
@@ -590,15 +611,23 @@ module ActiveRecord
590
611
  migrations_paths.first
591
612
  end
592
613
 
593
- def migrations(paths)
614
+ def migrations(paths, *args)
615
+ if args.empty?
616
+ subdirectories = true
617
+ else
618
+ subdirectories = args.first
619
+ ActiveSupport::Deprecation.warn "The `subdirectories` argument to `migrations` is deprecated"
620
+ end
621
+
594
622
  paths = Array.wrap(paths)
595
623
 
596
- files = Dir[*paths.map { |p| "#{p}/[0-9]*_*.rb" }]
624
+ glob = subdirectories ? "**/" : ""
625
+ files = Dir[*paths.map { |p| "#{p}/#{glob}[0-9]*_*.rb" }]
597
626
 
598
627
  seen = Hash.new false
599
628
 
600
629
  migrations = files.map do |file|
601
- version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
630
+ version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
602
631
 
603
632
  raise IllegalMigrationNameError.new(file) unless version
604
633
  version = version.to_i
@@ -609,7 +638,7 @@ module ActiveRecord
609
638
 
610
639
  seen[version] = seen[name] = true
611
640
 
612
- MigrationProxy.new(name, version, file)
641
+ MigrationProxy.new(name, version, file, scope)
613
642
  end
614
643
 
615
644
  migrations.sort_by(&:version)
@@ -652,7 +681,7 @@ module ActiveRecord
652
681
  end
653
682
  end
654
683
 
655
- def migrate
684
+ def migrate(&block)
656
685
  current = migrations.detect { |m| m.version == current_version }
657
686
  target = migrations.detect { |m| m.version == @target_version }
658
687
 
@@ -669,6 +698,10 @@ module ActiveRecord
669
698
 
670
699
  ran = []
671
700
  runnable.each do |migration|
701
+ if block && !block.call(migration)
702
+ next
703
+ end
704
+
672
705
  Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
673
706
 
674
707
  seen = migrated.include?(migration.version.to_i)