activerecord 4.1.16 → 4.2.11.3

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 +5 -5
  2. data/CHANGELOG.md +1162 -1801
  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 +83 -38
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  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/collection_association.rb +5 -1
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
  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 +63 -27
  18. data/lib/active_record/associations/collection_proxy.rb +29 -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 -13
  26. data/lib/active_record/associations/preloader/association.rb +14 -11
  27. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  28. data/lib/active_record/associations/preloader.rb +36 -26
  29. data/lib/active_record/associations/singular_association.rb +17 -2
  30. data/lib/active_record/associations/through_association.rb +5 -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 +19 -11
  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 -40
  42. data/lib/active_record/attribute_methods/write.rb +9 -24
  43. data/lib/active_record/attribute_methods.rb +56 -94
  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 +19 -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 +84 -52
  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 +138 -56
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
  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 +16 -32
  65. data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
  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 -388
  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 +131 -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 -39
  105. data/lib/active_record/counter_cache.rb +60 -6
  106. data/lib/active_record/enum.rb +9 -11
  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 +55 -69
  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 +71 -46
  119. data/lib/active_record/model_schema.rb +52 -58
  120. data/lib/active_record/nested_attributes.rb +5 -5
  121. data/lib/active_record/no_touching.rb +1 -1
  122. data/lib/active_record/persistence.rb +46 -26
  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 +18 -11
  126. data/lib/active_record/railties/databases.rake +50 -51
  127. data/lib/active_record/readonly_attributes.rb +0 -1
  128. data/lib/active_record/reflection.rb +273 -114
  129. data/lib/active_record/relation/batches.rb +0 -2
  130. data/lib/active_record/relation/calculations.rb +41 -37
  131. data/lib/active_record/relation/finder_methods.rb +70 -47
  132. data/lib/active_record/relation/merger.rb +39 -29
  133. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  134. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
  135. data/lib/active_record/relation/predicate_builder.rb +16 -8
  136. data/lib/active_record/relation/query_methods.rb +114 -65
  137. data/lib/active_record/relation/spawn_methods.rb +3 -0
  138. data/lib/active_record/relation.rb +57 -25
  139. data/lib/active_record/result.rb +18 -7
  140. data/lib/active_record/sanitization.rb +12 -2
  141. data/lib/active_record/schema.rb +0 -1
  142. data/lib/active_record/schema_dumper.rb +59 -28
  143. data/lib/active_record/schema_migration.rb +5 -4
  144. data/lib/active_record/scoping/default.rb +6 -4
  145. data/lib/active_record/scoping/named.rb +4 -0
  146. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  147. data/lib/active_record/statement_cache.rb +95 -10
  148. data/lib/active_record/store.rb +5 -5
  149. data/lib/active_record/tasks/database_tasks.rb +61 -6
  150. data/lib/active_record/tasks/mysql_database_tasks.rb +20 -11
  151. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  152. data/lib/active_record/timestamp.rb +9 -7
  153. data/lib/active_record/transactions.rb +53 -27
  154. data/lib/active_record/type/big_integer.rb +13 -0
  155. data/lib/active_record/type/binary.rb +50 -0
  156. data/lib/active_record/type/boolean.rb +31 -0
  157. data/lib/active_record/type/date.rb +50 -0
  158. data/lib/active_record/type/date_time.rb +54 -0
  159. data/lib/active_record/type/decimal.rb +64 -0
  160. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  161. data/lib/active_record/type/decorator.rb +14 -0
  162. data/lib/active_record/type/float.rb +19 -0
  163. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  164. data/lib/active_record/type/integer.rb +59 -0
  165. data/lib/active_record/type/mutable.rb +16 -0
  166. data/lib/active_record/type/numeric.rb +36 -0
  167. data/lib/active_record/type/serialized.rb +62 -0
  168. data/lib/active_record/type/string.rb +40 -0
  169. data/lib/active_record/type/text.rb +11 -0
  170. data/lib/active_record/type/time.rb +26 -0
  171. data/lib/active_record/type/time_value.rb +38 -0
  172. data/lib/active_record/type/type_map.rb +64 -0
  173. data/lib/active_record/type/unsigned_integer.rb +15 -0
  174. data/lib/active_record/type/value.rb +110 -0
  175. data/lib/active_record/type.rb +23 -0
  176. data/lib/active_record/validations/associated.rb +5 -3
  177. data/lib/active_record/validations/presence.rb +5 -3
  178. data/lib/active_record/validations/uniqueness.rb +25 -29
  179. data/lib/active_record/validations.rb +25 -19
  180. data/lib/active_record.rb +4 -0
  181. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  182. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +66 -11
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -2,6 +2,7 @@ require 'erb'
2
2
  require 'yaml'
3
3
  require 'zlib'
4
4
  require 'active_support/dependencies'
5
+ require 'active_support/core_ext/digest/uuid'
5
6
  require 'active_record/fixture_set/file'
6
7
  require 'active_record/errors'
7
8
 
@@ -14,9 +15,10 @@ module ActiveRecord
14
15
  # They are stored in YAML files, one file per model, which are placed in the directory
15
16
  # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
16
17
  # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
17
- # The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
18
- # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a fixture file looks
19
- # like this:
18
+ # The fixture file ends with the +.yml+ file extension, for example:
19
+ # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
20
+ #
21
+ # The format of a fixture file looks like this:
20
22
  #
21
23
  # rubyonrails:
22
24
  # id: 1
@@ -32,7 +34,7 @@ module ActiveRecord
32
34
  # is followed by an indented list of key/value pairs in the "key: value" format. Records are
33
35
  # separated by a blank line for your viewing pleasure.
34
36
  #
35
- # Note that fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
37
+ # Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
36
38
  # See http://yaml.org/type/omap.html
37
39
  # for the specification. You will need ordered fixtures when you have foreign key constraints
38
40
  # on keys in the same table. This is commonly needed for tree structures. Example:
@@ -60,8 +62,8 @@ module ActiveRecord
60
62
  # end
61
63
  # end
62
64
  #
63
- # By default, <tt>test_helper.rb</tt> will load all of your fixtures into your test database,
64
- # so this test will succeed.
65
+ # By default, +test_helper.rb+ will load all of your fixtures into your test
66
+ # database, so this test will succeed.
65
67
  #
66
68
  # The testing environment will automatically load the all fixtures into the database before each
67
69
  # test. To ensure consistent data, the environment deletes the fixtures before running the load.
@@ -179,6 +181,9 @@ module ActiveRecord
179
181
  # * Stable, autogenerated IDs
180
182
  # * Label references for associations (belongs_to, has_one, has_many)
181
183
  # * HABTM associations as inline lists
184
+ #
185
+ # There are some more advanced features available even if the id is specified:
186
+ #
182
187
  # * Autofilled timestamp columns
183
188
  # * Fixture label interpolation
184
189
  # * Support for YAML defaults
@@ -361,6 +366,7 @@ module ActiveRecord
361
366
  # geeksomnia:
362
367
  # name: Geeksomnia's Account
363
368
  # subdomain: $LABEL
369
+ # email: $LABEL@email.com
364
370
  #
365
371
  # Also, sometimes (like when porting older join table fixtures) you'll need
366
372
  # to be able to get a hold of the identifier for a given label. ERB
@@ -372,8 +378,9 @@ module ActiveRecord
372
378
  #
373
379
  # == Support for YAML defaults
374
380
  #
375
- # You probably already know how to use YAML to set and reuse defaults in
376
- # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
381
+ # You can set and reuse defaults in your fixtures YAML file.
382
+ # This is the same technique used in the +database.yml+ file to specify
383
+ # defaults:
377
384
  #
378
385
  # DEFAULTS: &DEFAULTS
379
386
  # created_on: <%= 3.weeks.ago.to_s(:db) %>
@@ -389,7 +396,8 @@ module ActiveRecord
389
396
  # Any fixture labeled "DEFAULTS" is safely ignored.
390
397
  class FixtureSet
391
398
  #--
392
- # An instance of FixtureSet is normally stored in a single YAML file and possibly in a folder with the same name.
399
+ # An instance of FixtureSet is normally stored in a single YAML file and
400
+ # possibly in a folder with the same name.
393
401
  #++
394
402
 
395
403
  MAX_ID = 2 ** 30 - 1
@@ -459,13 +467,7 @@ module ActiveRecord
459
467
  @config = config
460
468
 
461
469
  # Remove string values that aren't constants or subclasses of AR
462
- @class_names.delete_if { |k,klass|
463
- unless klass.is_a? Class
464
- klass = klass.safe_constantize
465
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `set_fixture_class` will be removed in Rails 4.2. Use the class itself instead.")
466
- end
467
- !insert_class(@class_names, k, klass)
468
- }
470
+ @class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
469
471
  end
470
472
 
471
473
  def [](fs_name)
@@ -516,14 +518,14 @@ module ActiveRecord
516
518
  ::File.join(fixtures_directory, fs_name))
517
519
  end
518
520
 
519
- all_loaded_fixtures.update(fixtures_map)
521
+ update_all_loaded_fixtures fixtures_map
520
522
 
521
523
  connection.transaction(:requires_new => true) do
522
524
  fixture_sets.each do |fs|
523
525
  conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
524
526
  table_rows = fs.table_rows
525
527
 
526
- table_rows.keys.each do |table|
528
+ table_rows.each_key do |table|
527
529
  conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
528
530
  end
529
531
 
@@ -547,9 +549,13 @@ module ActiveRecord
547
549
  end
548
550
 
549
551
  # Returns a consistent, platform-independent identifier for +label+.
550
- # Identifiers are positive integers less than 2^32.
551
- def self.identify(label)
552
- Zlib.crc32(label.to_s) % MAX_ID
552
+ # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
553
+ def self.identify(label, column_type = :integer)
554
+ if column_type == :uuid
555
+ Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
556
+ else
557
+ Zlib.crc32(label.to_s) % MAX_ID
558
+ end
553
559
  end
554
560
 
555
561
  # Superclass for the evaluation contexts used by ERB fixtures.
@@ -557,6 +563,10 @@ module ActiveRecord
557
563
  @context_class ||= Class.new
558
564
  end
559
565
 
566
+ def self.update_all_loaded_fixtures(fixtures_map) # :nodoc:
567
+ all_loaded_fixtures.update(fixtures_map)
568
+ end
569
+
560
570
  attr_reader :table_name, :name, :fixtures, :model_class, :config
561
571
 
562
572
  def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
@@ -565,10 +575,6 @@ module ActiveRecord
565
575
  @config = config
566
576
  @model_class = nil
567
577
 
568
- if class_name.is_a?(String)
569
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `FixtureSet.new` will be removed in Rails 4.2. Use the class itself instead.")
570
- end
571
-
572
578
  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
573
579
  @model_class = class_name
574
580
  else
@@ -625,12 +631,12 @@ module ActiveRecord
625
631
 
626
632
  # interpolate the fixture label
627
633
  row.each do |key, value|
628
- row[key] = label if "$LABEL" == value
634
+ row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
629
635
  end
630
636
 
631
637
  # generate a primary key if necessary
632
638
  if has_primary_key_column? && !row.include?(primary_key_name)
633
- row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
639
+ row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
634
640
  end
635
641
 
636
642
  # If STI is used, find the correct subclass for association reflection
@@ -641,19 +647,20 @@ module ActiveRecord
641
647
  model_class
642
648
  end
643
649
 
644
- reflection_class._reflections.values.each do |association|
650
+ reflection_class._reflections.each_value do |association|
645
651
  case association.macro
646
652
  when :belongs_to
647
653
  # Do not replace association name with association foreign key if they are named the same
648
654
  fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
649
655
 
650
656
  if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
651
- if association.options[:polymorphic] && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
657
+ if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
652
658
  # support polymorphic belongs_to as "label (Type)"
653
659
  row[association.foreign_type] = $1
654
660
  end
655
661
 
656
- row[fk_name] = ActiveRecord::FixtureSet.identify(value)
662
+ fk_type = reflection_class.columns_hash[fk_name].type
663
+ row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
657
664
  end
658
665
  when :has_many
659
666
  if association.options[:through]
@@ -680,6 +687,10 @@ module ActiveRecord
680
687
  def name
681
688
  @association.name
682
689
  end
690
+
691
+ def primary_key_type
692
+ @association.klass.column_types[@association.klass.primary_key].type
693
+ end
683
694
  end
684
695
 
685
696
  class HasManyThroughProxy < ReflectionProxy # :nodoc:
@@ -701,17 +712,22 @@ module ActiveRecord
701
712
  @primary_key_name ||= model_class && model_class.primary_key
702
713
  end
703
714
 
715
+ def primary_key_type
716
+ @primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
717
+ end
718
+
704
719
  def add_join_records(rows, row, association)
705
720
  # This is the case when the join table has no fixtures file
706
721
  if (targets = row.delete(association.name.to_s))
707
- table_name = association.join_table
708
- lhs_key = association.lhs_key
709
- rhs_key = association.rhs_key
722
+ table_name = association.join_table
723
+ column_type = association.primary_key_type
724
+ lhs_key = association.lhs_key
725
+ rhs_key = association.rhs_key
710
726
 
711
727
  targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
712
728
  rows[table_name].concat targets.map { |target|
713
729
  { lhs_key => row[primary_key_name],
714
- rhs_key => ActiveRecord::FixtureSet.identify(target) }
730
+ rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
715
731
  }
716
732
  end
717
733
  end
@@ -792,7 +808,9 @@ module ActiveRecord
792
808
 
793
809
  def find
794
810
  if model_class
795
- model_class.unscoped.find(fixture[model_class.primary_key])
811
+ model_class.unscoped do
812
+ model_class.find(fixture[model_class.primary_key])
813
+ end
796
814
  else
797
815
  raise FixtureClassNotFound, "No class attached to find."
798
816
  end
@@ -856,34 +874,9 @@ module ActiveRecord
856
874
  end
857
875
 
858
876
  self.fixture_table_names |= fixture_set_names
859
- require_fixture_classes(fixture_set_names, self.config)
860
877
  setup_fixture_accessors(fixture_set_names)
861
878
  end
862
879
 
863
- def try_to_load_dependency(file_name)
864
- require_dependency file_name
865
- rescue LoadError => e
866
- unless fixture_class_names.key?(file_name.pluralize)
867
- if ActiveRecord::Base.logger
868
- ActiveRecord::Base.logger.warn("Unable to load #{file_name}, make sure you added it to ActiveSupport::TestCase.set_fixture_class")
869
- ActiveRecord::Base.logger.warn("underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
870
- end
871
- end
872
- end
873
-
874
- def require_fixture_classes(fixture_set_names = nil, config = ActiveRecord::Base)
875
- if fixture_set_names
876
- fixture_set_names = fixture_set_names.map { |n| n.to_s }
877
- else
878
- fixture_set_names = fixture_table_names
879
- end
880
-
881
- fixture_set_names.each do |file_name|
882
- file_name = file_name.singularize if config.pluralize_table_names
883
- try_to_load_dependency(file_name)
884
- end
885
- end
886
-
887
880
  def setup_fixture_accessors(fixture_set_names = nil)
888
881
  fixture_set_names = Array(fixture_set_names || fixture_table_names)
889
882
  methods = Module.new do
@@ -960,7 +953,7 @@ module ActiveRecord
960
953
  end
961
954
 
962
955
  # Instantiate fixtures for every test if requested.
963
- instantiate_fixtures(config) if use_instantiated_fixtures
956
+ instantiate_fixtures if use_instantiated_fixtures
964
957
  end
965
958
 
966
959
  def teardown_fixtures
@@ -987,16 +980,9 @@ module ActiveRecord
987
980
  Hash[fixtures.map { |f| [f.name, f] }]
988
981
  end
989
982
 
990
- # for pre_loaded_fixtures, only require the classes once. huge speed improvement
991
- @@required_fixture_classes = false
992
-
993
- def instantiate_fixtures(config)
983
+ def instantiate_fixtures
994
984
  if pre_loaded_fixtures
995
985
  raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
996
- unless @@required_fixture_classes
997
- self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys, config
998
- @@required_fixture_classes = true
999
- end
1000
986
  ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
1001
987
  else
1002
988
  raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
@@ -1,14 +1,14 @@
1
1
  module ActiveRecord
2
- # Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt>
2
+ # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
3
3
  def self.gem_version
4
4
  Gem::Version.new VERSION::STRING
5
5
  end
6
6
 
7
7
  module VERSION
8
8
  MAJOR = 4
9
- MINOR = 1
10
- TINY = 16
11
- PRE = nil
9
+ MINOR = 2
10
+ TINY = 11
11
+ PRE = "3"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -1,6 +1,37 @@
1
1
  require 'active_support/core_ext/hash/indifferent_access'
2
2
 
3
3
  module ActiveRecord
4
+ # == Single table inheritance
5
+ #
6
+ # Active Record allows inheritance by storing the name of the class in a column that by
7
+ # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
8
+ # This means that an inheritance looking like this:
9
+ #
10
+ # class Company < ActiveRecord::Base; end
11
+ # class Firm < Company; end
12
+ # class Client < Company; end
13
+ # class PriorityClient < Client; end
14
+ #
15
+ # When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
16
+ # the companies table with type = "Firm". You can then fetch this row again using
17
+ # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
18
+ #
19
+ # Be aware that because the type column is an attribute on the record every new
20
+ # subclass will instantly be marked as dirty and the type column will be included
21
+ # in the list of changed attributes on the record. This is different from non
22
+ # STI classes:
23
+ #
24
+ # Company.new.changed? # => false
25
+ # Firm.new.changed? # => true
26
+ # Firm.new.changes # => {"type"=>["","Firm"]}
27
+ #
28
+ # If you don't have a type column defined in your table, single-table inheritance won't
29
+ # be triggered. In that case, it'll work just like normal subclasses with no special magic
30
+ # for differentiating between them or reloading the right type with find.
31
+ #
32
+ # Note, all the attributes for all the cases are kept in the same table. Read more:
33
+ # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
34
+ #
4
35
  module Inheritance
5
36
  extend ActiveSupport::Concern
6
37
 
@@ -49,12 +80,12 @@ module ActiveRecord
49
80
  end
50
81
 
51
82
  def symbolized_base_class
52
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_base_class is deprecated and will be removed without replacement.")
83
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
53
84
  @symbolized_base_class ||= base_class.to_s.to_sym
54
85
  end
55
86
 
56
87
  def symbolized_sti_name
57
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_sti_name is deprecated and will be removed without replacement.")
88
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
58
89
  @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
59
90
  end
60
91
 
@@ -120,14 +151,8 @@ module ActiveRecord
120
151
  candidates << type_name
121
152
 
122
153
  candidates.each do |candidate|
123
- begin
124
- constant = ActiveSupport::Dependencies.constantize(candidate)
125
- return constant if candidate == constant.to_s
126
- # We don't want to swallow NoMethodError < NameError errors
127
- rescue NoMethodError
128
- raise
129
- rescue NameError
130
- end
154
+ constant = ActiveSupport::Dependencies.safe_constantize(candidate)
155
+ return constant if candidate == constant.to_s
131
156
  end
132
157
 
133
158
  raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
@@ -55,16 +55,16 @@ module ActiveRecord
55
55
  def cache_key(*timestamp_names)
56
56
  case
57
57
  when new_record?
58
- "#{self.class.model_name.cache_key}/new"
58
+ "#{model_name.cache_key}/new"
59
59
  when timestamp_names.any?
60
60
  timestamp = max_updated_column_timestamp(timestamp_names)
61
61
  timestamp = timestamp.utc.to_s(cache_timestamp_format)
62
- "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
62
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
63
63
  when timestamp = max_updated_column_timestamp
64
64
  timestamp = timestamp.utc.to_s(cache_timestamp_format)
65
- "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
65
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
66
66
  else
67
- "#{self.class.model_name.cache_key}/#{id}"
67
+ "#{model_name.cache_key}/#{id}"
68
68
  end
69
69
  end
70
70
 
@@ -0,0 +1,30 @@
1
+ module ActiveRecord
2
+ module LegacyYamlAdapter
3
+ def self.convert(klass, coder)
4
+ return coder unless coder.is_a?(Psych::Coder)
5
+
6
+ case coder["active_record_yaml_version"]
7
+ when 0 then coder
8
+ else
9
+ if coder["attributes"].is_a?(AttributeSet)
10
+ coder
11
+ else
12
+ Rails41.convert(klass, coder)
13
+ end
14
+ end
15
+ end
16
+
17
+ module Rails41
18
+ def self.convert(klass, coder)
19
+ attributes = klass.attributes_builder
20
+ .build_from_database(coder["attributes"])
21
+ new_record = coder["attributes"][klass.primary_key].blank?
22
+
23
+ {
24
+ "attributes" => attributes,
25
+ "new_record" => new_record,
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -66,7 +66,16 @@ module ActiveRecord
66
66
  send(lock_col + '=', previous_lock_value + 1)
67
67
  end
68
68
 
69
- def _update_record(attribute_names = @attributes.keys) #:nodoc:
69
+ def _create_record(attribute_names = self.attribute_names, *) # :nodoc:
70
+ if locking_enabled?
71
+ # We always want to persist the locking version, even if we don't detect
72
+ # a change from the default, since the database might have no default
73
+ attribute_names |= [self.class.locking_column]
74
+ end
75
+ super
76
+ end
77
+
78
+ def _update_record(attribute_names = self.attribute_names) #:nodoc:
70
79
  return super unless locking_enabled?
71
80
  return 0 if attribute_names.empty?
72
81
 
@@ -80,17 +89,15 @@ module ActiveRecord
80
89
  begin
81
90
  relation = self.class.unscoped
82
91
 
83
- stmt = relation.where(
84
- relation.table[self.class.primary_key].eq(id).and(
85
- relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
86
- )
87
- ).arel.compile_update(
88
- arel_attributes_with_values_for_update(attribute_names),
89
- self.class.primary_key
92
+ affected_rows = relation.where(
93
+ self.class.primary_key => id,
94
+ lock_col => previous_lock_value,
95
+ ).update_all(
96
+ Hash[attributes_for_update(attribute_names).map do |name|
97
+ [name, _read_attribute(name)]
98
+ end]
90
99
  )
91
100
 
92
- affected_rows = self.class.connection.update stmt
93
-
94
101
  unless affected_rows == 1
95
102
  raise ActiveRecord::StaleObjectError.new(self, "update")
96
103
  end
@@ -120,7 +127,7 @@ module ActiveRecord
120
127
  if locking_enabled?
121
128
  column_name = self.class.locking_column
122
129
  column = self.class.columns_hash[column_name]
123
- substitute = self.class.connection.substitute_at(column, relation.bind_values.length)
130
+ substitute = self.class.connection.substitute_at(column)
124
131
 
125
132
  relation = relation.where(self.class.arel_table[column_name].eq(substitute))
126
133
  relation.bind_values << [column, self[column_name].to_i]
@@ -141,7 +148,7 @@ module ActiveRecord
141
148
 
142
149
  # Set the column to use for optimistic locking. Defaults to +lock_version+.
143
150
  def locking_column=(value)
144
- @column_defaults = nil
151
+ clear_caches_calculated_from_columns
145
152
  @locking_column = value.to_s
146
153
  end
147
154
 
@@ -151,12 +158,6 @@ module ActiveRecord
151
158
  @locking_column
152
159
  end
153
160
 
154
- # Quote the column name used for optimistic locking.
155
- def quoted_locking_column
156
- ActiveSupport::Deprecation.warn "ActiveRecord::Base.quoted_locking_column is deprecated and will be removed in Rails 4.2 or later."
157
- connection.quote_column_name(locking_column)
158
- end
159
-
160
161
  # Reset the column used for optimistic locking back to the +lock_version+ default.
161
162
  def reset_locking_column
162
163
  self.locking_column = DEFAULT_LOCKING_COLUMN
@@ -169,18 +170,37 @@ module ActiveRecord
169
170
  super
170
171
  end
171
172
 
172
- def column_defaults
173
- @column_defaults ||= begin
174
- defaults = super
175
-
176
- if defaults.key?(locking_column) && lock_optimistically
177
- defaults[locking_column] ||= 0
173
+ private
174
+
175
+ # We need to apply this decorator here, rather than on module inclusion. The closure
176
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
177
+ # sub class being decorated. As such, changes to `lock_optimistically`, or
178
+ # `locking_column` would not be picked up.
179
+ def inherited(subclass)
180
+ subclass.class_eval do
181
+ is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
182
+ decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
183
+ LockingType.new(type)
178
184
  end
179
-
180
- defaults
181
185
  end
186
+ super
182
187
  end
183
188
  end
184
189
  end
190
+
191
+ class LockingType < SimpleDelegator # :nodoc:
192
+ def type_cast_from_database(value)
193
+ # `nil` *should* be changed to 0
194
+ super.to_i
195
+ end
196
+
197
+ def init_with(coder)
198
+ __setobj__(coder['subtype'])
199
+ end
200
+
201
+ def encode_with(coder)
202
+ coder['subtype'] = __getobj__
203
+ end
204
+ end
185
205
  end
186
206
  end
@@ -74,7 +74,9 @@ module ActiveRecord
74
74
  :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
75
75
  :change_column_default, :add_reference, :remove_reference, :transaction,
76
76
  :drop_join_table, :drop_table, :execute_block, :enable_extension,
77
- :change_column, :execute, :remove_columns, :change_column_null # irreversible methods need to be here too
77
+ :change_column, :execute, :remove_columns, :change_column_null,
78
+ :add_foreign_key, :remove_foreign_key
79
+ # irreversible methods need to be here too
78
80
  ].each do |method|
79
81
  class_eval <<-EOV, __FILE__, __LINE__ + 1
80
82
  def #{method}(*args, &block) # def create_table(*args, &block)
@@ -85,7 +87,7 @@ module ActiveRecord
85
87
  alias :add_belongs_to :add_reference
86
88
  alias :remove_belongs_to :remove_reference
87
89
 
88
- def change_table(table_name, options = {})
90
+ def change_table(table_name, options = {}) # :nodoc:
89
91
  yield delegate.update_table_definition(table_name, self)
90
92
  end
91
93
 
@@ -167,6 +169,21 @@ module ActiveRecord
167
169
  [:change_column_null, args]
168
170
  end
169
171
 
172
+ def invert_add_foreign_key(args)
173
+ from_table, to_table, add_options = args
174
+ add_options ||= {}
175
+
176
+ if add_options[:name]
177
+ options = { name: add_options[:name] }
178
+ elsif add_options[:column]
179
+ options = { column: add_options[:column] }
180
+ else
181
+ options = to_table
182
+ end
183
+
184
+ [:remove_foreign_key, [from_table, options]]
185
+ end
186
+
170
187
  # Forwards any missing method call to the \target.
171
188
  def method_missing(method, *args, &block)
172
189
  if @delegate.respond_to?(method)
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  end
9
9
 
10
10
  def join_table_name(table_1, table_2)
11
- [table_1.to_s, table_2.to_s].sort.join("_").to_sym
11
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
12
12
  end
13
13
  end
14
14
  end