activerecord 4.1.8 → 4.2.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1165 -1591
- 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 +84 -43
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +16 -5
- 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 +9 -14
- 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 +87 -30
- data/lib/active_record/associations/collection_proxy.rb +33 -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 -12
- data/lib/active_record/associations/preloader/association.rb +14 -10
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +37 -26
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +16 -12
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +20 -12
- 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 -28
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_methods.rb +57 -95
- 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 +30 -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 +85 -53
- 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 +139 -57
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
- 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 +17 -33
- data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
- 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 -385
- 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 +134 -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 -40
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +10 -12
- 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 +62 -74
- 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 +79 -47
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +18 -8
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +48 -27
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +19 -14
- data/lib/active_record/railties/databases.rake +55 -56
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +281 -117
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +71 -48
- 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 -1
- data/lib/active_record/relation/predicate_builder.rb +42 -12
- data/lib/active_record/relation/query_methods.rb +130 -73
- data/lib/active_record/relation/spawn_methods.rb +10 -3
- 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 -8
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- 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 +54 -28
- 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 +24 -20
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +5 -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
|
|
@@ -532,12 +534,10 @@ module ActiveRecord
|
|
532
534
|
conn.insert_fixture(row, fixture_set_name)
|
533
535
|
end
|
534
536
|
end
|
535
|
-
end
|
536
537
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
connection.reset_pk_sequence!(fs.table_name)
|
538
|
+
# Cap primary key sequences to max(pk).
|
539
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
540
|
+
conn.reset_pk_sequence!(fs.table_name)
|
541
541
|
end
|
542
542
|
end
|
543
543
|
end
|
@@ -549,9 +549,13 @@ module ActiveRecord
|
|
549
549
|
end
|
550
550
|
|
551
551
|
# Returns a consistent, platform-independent identifier for +label+.
|
552
|
-
#
|
553
|
-
def self.identify(label)
|
554
|
-
|
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
|
555
559
|
end
|
556
560
|
|
557
561
|
# Superclass for the evaluation contexts used by ERB fixtures.
|
@@ -559,6 +563,10 @@ module ActiveRecord
|
|
559
563
|
@context_class ||= Class.new
|
560
564
|
end
|
561
565
|
|
566
|
+
def self.update_all_loaded_fixtures(fixtures_map) # :nodoc:
|
567
|
+
all_loaded_fixtures.update(fixtures_map)
|
568
|
+
end
|
569
|
+
|
562
570
|
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
563
571
|
|
564
572
|
def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
|
@@ -567,10 +575,6 @@ module ActiveRecord
|
|
567
575
|
@config = config
|
568
576
|
@model_class = nil
|
569
577
|
|
570
|
-
if class_name.is_a?(String)
|
571
|
-
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.")
|
572
|
-
end
|
573
|
-
|
574
578
|
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
575
579
|
@model_class = class_name
|
576
580
|
else
|
@@ -627,12 +631,12 @@ module ActiveRecord
|
|
627
631
|
|
628
632
|
# interpolate the fixture label
|
629
633
|
row.each do |key, value|
|
630
|
-
row[key] =
|
634
|
+
row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
|
631
635
|
end
|
632
636
|
|
633
637
|
# generate a primary key if necessary
|
634
638
|
if has_primary_key_column? && !row.include?(primary_key_name)
|
635
|
-
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
|
639
|
+
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
|
636
640
|
end
|
637
641
|
|
638
642
|
# If STI is used, find the correct subclass for association reflection
|
@@ -643,19 +647,20 @@ module ActiveRecord
|
|
643
647
|
model_class
|
644
648
|
end
|
645
649
|
|
646
|
-
reflection_class._reflections.
|
650
|
+
reflection_class._reflections.each_value do |association|
|
647
651
|
case association.macro
|
648
652
|
when :belongs_to
|
649
653
|
# Do not replace association name with association foreign key if they are named the same
|
650
654
|
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
651
655
|
|
652
656
|
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
653
|
-
if association.
|
657
|
+
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
654
658
|
# support polymorphic belongs_to as "label (Type)"
|
655
659
|
row[association.foreign_type] = $1
|
656
660
|
end
|
657
661
|
|
658
|
-
|
662
|
+
fk_type = reflection_class.columns_hash[fk_name].type
|
663
|
+
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
659
664
|
end
|
660
665
|
when :has_many
|
661
666
|
if association.options[:through]
|
@@ -682,6 +687,10 @@ module ActiveRecord
|
|
682
687
|
def name
|
683
688
|
@association.name
|
684
689
|
end
|
690
|
+
|
691
|
+
def primary_key_type
|
692
|
+
@association.klass.column_types[@association.klass.primary_key].type
|
693
|
+
end
|
685
694
|
end
|
686
695
|
|
687
696
|
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
@@ -692,6 +701,10 @@ module ActiveRecord
|
|
692
701
|
def lhs_key
|
693
702
|
@association.through_reflection.foreign_key
|
694
703
|
end
|
704
|
+
|
705
|
+
def join_table
|
706
|
+
@association.through_reflection.table_name
|
707
|
+
end
|
695
708
|
end
|
696
709
|
|
697
710
|
private
|
@@ -699,17 +712,22 @@ module ActiveRecord
|
|
699
712
|
@primary_key_name ||= model_class && model_class.primary_key
|
700
713
|
end
|
701
714
|
|
715
|
+
def primary_key_type
|
716
|
+
@primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
|
717
|
+
end
|
718
|
+
|
702
719
|
def add_join_records(rows, row, association)
|
703
720
|
# This is the case when the join table has no fixtures file
|
704
721
|
if (targets = row.delete(association.name.to_s))
|
705
|
-
table_name
|
706
|
-
|
707
|
-
|
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
|
708
726
|
|
709
727
|
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
710
728
|
rows[table_name].concat targets.map { |target|
|
711
729
|
{ lhs_key => row[primary_key_name],
|
712
|
-
rhs_key => ActiveRecord::FixtureSet.identify(target) }
|
730
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
713
731
|
}
|
714
732
|
end
|
715
733
|
end
|
@@ -790,7 +808,9 @@ module ActiveRecord
|
|
790
808
|
|
791
809
|
def find
|
792
810
|
if model_class
|
793
|
-
model_class.
|
811
|
+
model_class.unscoped do
|
812
|
+
model_class.find(fixture[model_class.primary_key])
|
813
|
+
end
|
794
814
|
else
|
795
815
|
raise FixtureClassNotFound, "No class attached to find."
|
796
816
|
end
|
@@ -854,34 +874,9 @@ module ActiveRecord
|
|
854
874
|
end
|
855
875
|
|
856
876
|
self.fixture_table_names |= fixture_set_names
|
857
|
-
require_fixture_classes(fixture_set_names, self.config)
|
858
877
|
setup_fixture_accessors(fixture_set_names)
|
859
878
|
end
|
860
879
|
|
861
|
-
def try_to_load_dependency(file_name)
|
862
|
-
require_dependency file_name
|
863
|
-
rescue LoadError => e
|
864
|
-
unless fixture_class_names.key?(file_name.pluralize)
|
865
|
-
if ActiveRecord::Base.logger
|
866
|
-
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, make sure you added it to ActiveSupport::TestCase.set_fixture_class")
|
867
|
-
ActiveRecord::Base.logger.warn("underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
868
|
-
end
|
869
|
-
end
|
870
|
-
end
|
871
|
-
|
872
|
-
def require_fixture_classes(fixture_set_names = nil, config = ActiveRecord::Base)
|
873
|
-
if fixture_set_names
|
874
|
-
fixture_set_names = fixture_set_names.map { |n| n.to_s }
|
875
|
-
else
|
876
|
-
fixture_set_names = fixture_table_names
|
877
|
-
end
|
878
|
-
|
879
|
-
fixture_set_names.each do |file_name|
|
880
|
-
file_name = file_name.singularize if config.pluralize_table_names
|
881
|
-
try_to_load_dependency(file_name)
|
882
|
-
end
|
883
|
-
end
|
884
|
-
|
885
880
|
def setup_fixture_accessors(fixture_set_names = nil)
|
886
881
|
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
887
882
|
methods = Module.new do
|
@@ -958,7 +953,7 @@ module ActiveRecord
|
|
958
953
|
end
|
959
954
|
|
960
955
|
# Instantiate fixtures for every test if requested.
|
961
|
-
instantiate_fixtures
|
956
|
+
instantiate_fixtures if use_instantiated_fixtures
|
962
957
|
end
|
963
958
|
|
964
959
|
def teardown_fixtures
|
@@ -985,16 +980,9 @@ module ActiveRecord
|
|
985
980
|
Hash[fixtures.map { |f| [f.name, f] }]
|
986
981
|
end
|
987
982
|
|
988
|
-
|
989
|
-
@@required_fixture_classes = false
|
990
|
-
|
991
|
-
def instantiate_fixtures(config)
|
983
|
+
def instantiate_fixtures
|
992
984
|
if pre_loaded_fixtures
|
993
985
|
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
994
|
-
unless @@required_fixture_classes
|
995
|
-
self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys, config
|
996
|
-
@@required_fixture_classes = true
|
997
|
-
end
|
998
986
|
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
999
987
|
else
|
1000
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)
|