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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1162 -1801
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_methods.rb +56 -94
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +71 -46
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +20 -11
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +4 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- 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
|
18
|
-
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
19
|
-
#
|
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
|
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,
|
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
|
376
|
-
#
|
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
|
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 { |
|
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
|
-
|
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.
|
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
|
-
#
|
551
|
-
def self.identify(label)
|
552
|
-
|
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] =
|
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.
|
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.
|
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
|
-
|
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
|
708
|
-
|
709
|
-
|
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
|
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
|
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
|
-
|
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
|
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 =
|
10
|
-
TINY =
|
11
|
-
PRE =
|
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(
|
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(
|
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
|
-
|
124
|
-
|
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
|
-
"#{
|
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
|
-
"#{
|
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
|
-
"#{
|
65
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
66
66
|
else
|
67
|
-
"#{
|
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
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
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
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
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)
|