activerecord 5.0.7.2 → 5.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +389 -2252
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record.rb +20 -20
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations.rb +1579 -1569
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +23 -15
- data/lib/active_record/associations/association_scope.rb +83 -81
- data/lib/active_record/associations/belongs_to_association.rb +0 -1
- data/lib/active_record/associations/builder/belongs_to.rb +16 -14
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +74 -241
- data/lib/active_record/associations/collection_proxy.rb +144 -70
- data/lib/active_record/associations/has_many_association.rb +15 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -5
- data/lib/active_record/associations/has_one_association.rb +22 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +117 -115
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/preloader/association.rb +87 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +34 -41
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +3 -6
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +216 -34
- data/lib/active_record/attribute_methods/primary_key.rb +78 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +36 -30
- data/lib/active_record/attribute_mutation_tracker.rb +53 -10
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attribute_set/builder.rb +41 -49
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attributes.rb +21 -21
- data/lib/active_record/autosave_association.rb +13 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +52 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +6 -17
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
- data/lib/active_record/connection_adapters/column.rb +27 -5
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +110 -93
- data/lib/active_record/counter_cache.rb +62 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +58 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +64 -56
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +29 -29
- data/lib/active_record/migration.rb +155 -172
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +76 -37
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/model_schema.rb +85 -119
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +10 -33
- data/lib/active_record/persistence.rb +45 -38
- data/lib/active_record/query_cache.rb +4 -8
- data/lib/active_record/querying.rb +2 -3
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +125 -140
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +79 -96
- data/lib/active_record/relation.rb +72 -115
- data/lib/active_record/relation/batches.rb +87 -58
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/calculations.rb +154 -160
- data/lib/active_record/relation/delegation.rb +30 -29
- data/lib/active_record/relation/finder_methods.rb +195 -226
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +247 -295
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +79 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/result.rb +29 -31
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +182 -197
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +14 -37
- data/lib/active_record/schema_migration.rb +3 -3
- data/lib/active_record/scoping.rb +9 -10
- data/lib/active_record/scoping/default.rb +87 -91
- data/lib/active_record/scoping/named.rb +16 -28
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +72 -65
- data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
- data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +98 -110
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +9 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/serialized.rb +8 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +4 -4
- data/lib/rails/generators/active_record/migration.rb +2 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- metadata +22 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/notifications"
|
2
|
+
require "active_record/explain_registry"
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
class ExplainSubscriber # :nodoc:
|
@@ -18,10 +18,13 @@ module ActiveRecord
|
|
18
18
|
#
|
19
19
|
# On the other hand, we want to monitor the performance of our real database
|
20
20
|
# queries, not the performance of the access to the query cache.
|
21
|
-
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN
|
21
|
+
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
|
22
22
|
EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
|
23
23
|
def ignore_payload?(payload)
|
24
|
-
payload[:exception] ||
|
24
|
+
payload[:exception] ||
|
25
|
+
payload[:cached] ||
|
26
|
+
IGNORED_PAYLOADS.include?(payload[:name]) ||
|
27
|
+
payload[:sql] !~ EXPLAINED_SQLS
|
25
28
|
end
|
26
29
|
|
27
30
|
ActiveSupport::Notifications.subscribe("sql.active_record", new)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "erb"
|
2
|
+
require "yaml"
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
class FixtureSet
|
@@ -24,21 +24,21 @@ module ActiveRecord
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def model_class
|
27
|
-
config_row[
|
27
|
+
config_row["model_class"]
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
31
|
def rows
|
32
|
-
@rows ||= raw_rows.reject { |fixture_name, _| fixture_name ==
|
32
|
+
@rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
|
33
33
|
end
|
34
34
|
|
35
35
|
def config_row
|
36
36
|
@config_row ||= begin
|
37
|
-
row = raw_rows.find { |fixture_name, _| fixture_name ==
|
37
|
+
row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
|
38
38
|
if row
|
39
39
|
row.last
|
40
40
|
else
|
41
|
-
{'model_class': nil}
|
41
|
+
{ 'model_class': nil }
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -66,10 +66,13 @@ module ActiveRecord
|
|
66
66
|
# Validate our unmarshalled data.
|
67
67
|
def validate(data)
|
68
68
|
unless Hash === data || YAML::Omap === data
|
69
|
-
raise Fixture::FormatError,
|
69
|
+
raise Fixture::FormatError, "fixture is not a hash: #{@file}"
|
70
70
|
end
|
71
71
|
|
72
|
-
|
72
|
+
invalid = data.reject { |_, row| Hash === row }
|
73
|
+
if invalid.any?
|
74
|
+
raise Fixture::FormatError, "fixture key is not a hash: #{@file}, keys: #{invalid.keys.inspect}"
|
75
|
+
end
|
73
76
|
data
|
74
77
|
end
|
75
78
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
1
|
+
require "erb"
|
2
|
+
require "yaml"
|
3
|
+
require "zlib"
|
4
|
+
require "set"
|
5
|
+
require "active_support/dependencies"
|
6
|
+
require "active_support/core_ext/digest/uuid"
|
7
|
+
require "active_record/fixture_set/file"
|
8
|
+
require "active_record/errors"
|
9
9
|
|
10
10
|
module ActiveRecord
|
11
11
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
# By default, +test_helper.rb+ will load all of your fixtures into your test
|
67
67
|
# database, so this test will succeed.
|
68
68
|
#
|
69
|
-
# The testing environment will automatically load the
|
69
|
+
# The testing environment will automatically load all the fixtures into the database before each
|
70
70
|
# test. To ensure consistent data, the environment deletes the fixtures before running the load.
|
71
71
|
#
|
72
72
|
# In addition to being available in the database, the fixture's data may also be accessed by
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
88
88
|
# assert_equal "Ruby on Rails", @rubyonrails.name
|
89
89
|
# end
|
90
90
|
#
|
91
|
-
# In order to use these methods to access fixtured data within your
|
91
|
+
# In order to use these methods to access fixtured data within your test cases, you must specify one of the
|
92
92
|
# following in your ActiveSupport::TestCase-derived class:
|
93
93
|
#
|
94
94
|
# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
103
103
|
#
|
104
104
|
# = Dynamic fixtures with ERB
|
105
105
|
#
|
106
|
-
#
|
106
|
+
# Sometimes you don't care about the content of the fixtures as much as you care about the volume.
|
107
107
|
# In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
|
108
108
|
# testing, like:
|
109
109
|
#
|
@@ -415,9 +415,9 @@ module ActiveRecord
|
|
415
415
|
# possibly in a folder with the same name.
|
416
416
|
#++
|
417
417
|
|
418
|
-
MAX_ID = 2
|
418
|
+
MAX_ID = 2**30 - 1
|
419
419
|
|
420
|
-
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
|
420
|
+
@@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
|
421
421
|
|
422
422
|
def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
423
423
|
config.pluralize_table_names ?
|
@@ -426,9 +426,9 @@ module ActiveRecord
|
|
426
426
|
end
|
427
427
|
|
428
428
|
def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
429
|
-
|
430
|
-
|
431
|
-
|
429
|
+
"#{ config.table_name_prefix }"\
|
430
|
+
"#{ fixture_set_name.tr('/', '_') }"\
|
431
|
+
"#{ config.table_name_suffix }".to_sym
|
432
432
|
end
|
433
433
|
|
434
434
|
def self.reset_cache
|
@@ -494,18 +494,18 @@ module ActiveRecord
|
|
494
494
|
|
495
495
|
private
|
496
496
|
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
497
|
+
def insert_class(class_names, name, klass)
|
498
|
+
# We only want to deal with AR objects.
|
499
|
+
if klass && klass < ActiveRecord::Base
|
500
|
+
class_names[name] = klass
|
501
|
+
else
|
502
|
+
class_names[name] = nil
|
503
|
+
end
|
503
504
|
end
|
504
|
-
end
|
505
505
|
|
506
|
-
|
507
|
-
|
508
|
-
|
506
|
+
def default_fixture_model(fs_name, config)
|
507
|
+
ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
|
508
|
+
end
|
509
509
|
end
|
510
510
|
|
511
511
|
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
@@ -597,18 +597,18 @@ module ActiveRecord
|
|
597
597
|
|
598
598
|
@fixtures = read_fixture_files(path)
|
599
599
|
|
600
|
-
@connection
|
600
|
+
@connection = connection
|
601
601
|
|
602
|
-
@table_name = (
|
602
|
+
@table_name = (model_class.respond_to?(:table_name) ?
|
603
603
|
model_class.table_name :
|
604
|
-
self.class.default_fixture_table_name(name, config)
|
604
|
+
self.class.default_fixture_table_name(name, config))
|
605
605
|
end
|
606
606
|
|
607
607
|
def [](x)
|
608
608
|
fixtures[x]
|
609
609
|
end
|
610
610
|
|
611
|
-
def []=(k,v)
|
611
|
+
def []=(k, v)
|
612
612
|
fixtures[k] = v
|
613
613
|
end
|
614
614
|
|
@@ -626,10 +626,10 @@ module ActiveRecord
|
|
626
626
|
now = config.default_timezone == :utc ? Time.now.utc : Time.now
|
627
627
|
|
628
628
|
# allow a standard key to be used for doing defaults in YAML
|
629
|
-
fixtures.delete(
|
629
|
+
fixtures.delete("DEFAULTS")
|
630
630
|
|
631
631
|
# track any join tables we need to insert later
|
632
|
-
rows = Hash.new { |h,table| h[table] = [] }
|
632
|
+
rows = Hash.new { |h, table| h[table] = [] }
|
633
633
|
|
634
634
|
rows[table_name] = fixtures.map do |label, fixture|
|
635
635
|
row = fixture.to_hash
|
@@ -799,7 +799,6 @@ module ActiveRecord
|
|
799
799
|
def yaml_file_path(path)
|
800
800
|
"#{path}.yml"
|
801
801
|
end
|
802
|
-
|
803
802
|
end
|
804
803
|
|
805
804
|
class Fixture #:nodoc:
|
@@ -859,33 +858,21 @@ module ActiveRecord
|
|
859
858
|
end
|
860
859
|
|
861
860
|
included do
|
862
|
-
class_attribute :fixture_path, :
|
861
|
+
class_attribute :fixture_path, instance_writer: false
|
863
862
|
class_attribute :fixture_table_names
|
864
863
|
class_attribute :fixture_class_names
|
865
864
|
class_attribute :use_transactional_tests
|
866
|
-
class_attribute :use_transactional_fixtures
|
867
865
|
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
|
868
866
|
class_attribute :pre_loaded_fixtures
|
869
867
|
class_attribute :config
|
870
868
|
|
871
|
-
singleton_class.deprecate 'use_transactional_fixtures=' => 'use use_transactional_tests= instead'
|
872
|
-
|
873
869
|
self.fixture_table_names = []
|
874
870
|
self.use_instantiated_fixtures = false
|
875
871
|
self.pre_loaded_fixtures = false
|
876
872
|
self.config = ActiveRecord::Base
|
877
873
|
|
878
874
|
self.fixture_class_names = {}
|
879
|
-
|
880
|
-
silence_warnings do
|
881
|
-
define_singleton_method :use_transactional_tests do
|
882
|
-
if use_transactional_fixtures.nil?
|
883
|
-
true
|
884
|
-
else
|
885
|
-
use_transactional_fixtures
|
886
|
-
end
|
887
|
-
end
|
888
|
-
end
|
875
|
+
self.use_transactional_tests = true
|
889
876
|
end
|
890
877
|
|
891
878
|
module ClassMethods
|
@@ -898,12 +885,12 @@ module ActiveRecord
|
|
898
885
|
#
|
899
886
|
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
900
887
|
def set_fixture_class(class_names = {})
|
901
|
-
self.fixture_class_names =
|
888
|
+
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
902
889
|
end
|
903
890
|
|
904
891
|
def fixtures(*fixture_set_names)
|
905
892
|
if fixture_set_names.first == :all
|
906
|
-
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
|
893
|
+
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
|
907
894
|
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
908
895
|
else
|
909
896
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
@@ -918,7 +905,7 @@ module ActiveRecord
|
|
918
905
|
methods = Module.new do
|
919
906
|
fixture_set_names.each do |fs_name|
|
920
907
|
fs_name = fs_name.to_s
|
921
|
-
accessor_name = fs_name.tr(
|
908
|
+
accessor_name = fs_name.tr("/", "_").to_sym
|
922
909
|
|
923
910
|
define_method(accessor_name) do |*fixture_names|
|
924
911
|
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
@@ -962,12 +949,13 @@ module ActiveRecord
|
|
962
949
|
|
963
950
|
def setup_fixtures(config = ActiveRecord::Base)
|
964
951
|
if pre_loaded_fixtures && !use_transactional_tests
|
965
|
-
raise RuntimeError,
|
952
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
966
953
|
end
|
967
954
|
|
968
955
|
@fixture_cache = {}
|
969
956
|
@fixture_connections = []
|
970
957
|
@@already_loaded_fixtures ||= {}
|
958
|
+
@connection_subscriber = nil
|
971
959
|
|
972
960
|
# Load fixtures once and begin transaction.
|
973
961
|
if run_in_transaction?
|
@@ -977,10 +965,33 @@ module ActiveRecord
|
|
977
965
|
@loaded_fixtures = load_fixtures(config)
|
978
966
|
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
979
967
|
end
|
968
|
+
|
969
|
+
# Begin transactions for connections already established
|
980
970
|
@fixture_connections = enlist_fixture_connections
|
981
971
|
@fixture_connections.each do |connection|
|
982
972
|
connection.begin_transaction joinable: false
|
973
|
+
connection.pool.lock_thread = true
|
983
974
|
end
|
975
|
+
|
976
|
+
# When connections are established in the future, begin a transaction too
|
977
|
+
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
978
|
+
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
979
|
+
|
980
|
+
if spec_name
|
981
|
+
begin
|
982
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
983
|
+
rescue ConnectionNotEstablished
|
984
|
+
connection = nil
|
985
|
+
end
|
986
|
+
|
987
|
+
if connection && !@fixture_connections.include?(connection)
|
988
|
+
connection.begin_transaction joinable: false
|
989
|
+
connection.pool.lock_thread = true
|
990
|
+
@fixture_connections << connection
|
991
|
+
end
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
984
995
|
# Load fixtures for every test.
|
985
996
|
else
|
986
997
|
ActiveRecord::FixtureSet.reset_cache
|
@@ -995,8 +1006,10 @@ module ActiveRecord
|
|
995
1006
|
def teardown_fixtures
|
996
1007
|
# Rollback changes if a transaction is active.
|
997
1008
|
if run_in_transaction?
|
1009
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
998
1010
|
@fixture_connections.each do |connection|
|
999
1011
|
connection.rollback_transaction if connection.transaction_open?
|
1012
|
+
connection.pool.lock_thread = false
|
1000
1013
|
end
|
1001
1014
|
@fixture_connections.clear
|
1002
1015
|
else
|
@@ -1018,10 +1031,10 @@ module ActiveRecord
|
|
1018
1031
|
|
1019
1032
|
def instantiate_fixtures
|
1020
1033
|
if pre_loaded_fixtures
|
1021
|
-
raise RuntimeError,
|
1034
|
+
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
1022
1035
|
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
1023
1036
|
else
|
1024
|
-
raise RuntimeError,
|
1037
|
+
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
1025
1038
|
@loaded_fixtures.each_value do |fixture_set|
|
1026
1039
|
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
1027
1040
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/core_ext/hash/indifferent_access"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
# == Single table inheritance
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
# Be aware that because the type column is an attribute on the record every new
|
20
20
|
# subclass will instantly be marked as dirty and the type column will be included
|
21
21
|
# in the list of changed attributes on the record. This is different from non
|
22
|
-
# STI classes:
|
22
|
+
# Single Table Inheritance(STI) classes:
|
23
23
|
#
|
24
24
|
# Company.new.changed? # => false
|
25
25
|
# Firm.new.changed? # => true
|
@@ -37,6 +37,7 @@ module ActiveRecord
|
|
37
37
|
|
38
38
|
included do
|
39
39
|
# Determines whether to store the full constant name including namespace when using STI.
|
40
|
+
# This is true, by default.
|
40
41
|
class_attribute :store_full_sti_class, instance_writer: false
|
41
42
|
self.store_full_sti_class = true
|
42
43
|
end
|
@@ -129,87 +130,100 @@ module ActiveRecord
|
|
129
130
|
store_full_sti_class ? name : name.demodulize
|
130
131
|
end
|
131
132
|
|
133
|
+
def inherited(subclass)
|
134
|
+
subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
|
135
|
+
super
|
136
|
+
end
|
137
|
+
|
132
138
|
protected
|
133
139
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
140
|
+
# Returns the class type of the record using the current module as a prefix. So descendants of
|
141
|
+
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
|
142
|
+
def compute_type(type_name)
|
143
|
+
if type_name.start_with?("::".freeze)
|
144
|
+
# If the type is prefixed with a scope operator then we assume that
|
145
|
+
# the type_name is an absolute reference.
|
146
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
147
|
+
else
|
148
|
+
type_candidate = @_type_candidates_cache[type_name]
|
149
|
+
if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
|
150
|
+
return type_constant
|
151
|
+
end
|
152
|
+
|
153
|
+
# Build a list of candidates to search for
|
154
|
+
candidates = []
|
155
|
+
name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
|
156
|
+
candidates << type_name
|
157
|
+
|
158
|
+
candidates.each do |candidate|
|
159
|
+
constant = ActiveSupport::Dependencies.safe_constantize(candidate)
|
160
|
+
if candidate == constant.to_s
|
161
|
+
@_type_candidates_cache[type_name] = candidate
|
162
|
+
return constant
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
|
150
167
|
end
|
151
|
-
|
152
|
-
raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
|
153
168
|
end
|
154
|
-
end
|
155
169
|
|
156
170
|
private
|
157
171
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
172
|
+
# Called by +instantiate+ to decide which class to use for a new
|
173
|
+
# record instance. For single-table inheritance, we check the record
|
174
|
+
# for a +type+ column and return the corresponding class.
|
175
|
+
def discriminate_class_for_record(record)
|
176
|
+
if using_single_table_inheritance?(record)
|
177
|
+
find_sti_class(record[inheritance_column])
|
178
|
+
else
|
179
|
+
super
|
180
|
+
end
|
166
181
|
end
|
167
|
-
end
|
168
182
|
|
169
|
-
|
170
|
-
|
171
|
-
|
183
|
+
def using_single_table_inheritance?(record)
|
184
|
+
record[inheritance_column].present? && has_attribute?(inheritance_column)
|
185
|
+
end
|
172
186
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
187
|
+
def find_sti_class(type_name)
|
188
|
+
type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
|
189
|
+
subclass = begin
|
190
|
+
if store_full_sti_class
|
191
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
192
|
+
else
|
193
|
+
compute_type(type_name)
|
194
|
+
end
|
195
|
+
rescue NameError
|
196
|
+
raise SubclassNotFound,
|
197
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
198
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
199
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
200
|
+
"or overwrite #{name}.inheritance_column to use another column for that information."
|
180
201
|
end
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
186
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
187
|
-
end
|
188
|
-
unless subclass == self || descendants.include?(subclass)
|
189
|
-
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
202
|
+
unless subclass == self || descendants.include?(subclass)
|
203
|
+
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
204
|
+
end
|
205
|
+
subclass
|
190
206
|
end
|
191
|
-
subclass
|
192
|
-
end
|
193
207
|
|
194
|
-
|
195
|
-
|
196
|
-
|
208
|
+
def type_condition(table = arel_table)
|
209
|
+
sti_column = arel_attribute(inheritance_column, table)
|
210
|
+
sti_names = ([self] + descendants).map(&:sti_name)
|
197
211
|
|
198
|
-
|
199
|
-
|
212
|
+
sti_column.in(sti_names)
|
213
|
+
end
|
200
214
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
215
|
+
# Detect the subclass from the inheritance column of attrs. If the inheritance column value
|
216
|
+
# is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
|
217
|
+
def subclass_from_attributes(attrs)
|
218
|
+
attrs = attrs.to_h if attrs.respond_to?(:permitted?)
|
219
|
+
if attrs.is_a?(Hash)
|
220
|
+
subclass_name = attrs.with_indifferent_access[inheritance_column]
|
207
221
|
|
208
|
-
|
209
|
-
|
222
|
+
if subclass_name.present?
|
223
|
+
find_sti_class(subclass_name)
|
224
|
+
end
|
210
225
|
end
|
211
226
|
end
|
212
|
-
end
|
213
227
|
end
|
214
228
|
|
215
229
|
def initialize_dup(other)
|
@@ -219,21 +233,21 @@ module ActiveRecord
|
|
219
233
|
|
220
234
|
private
|
221
235
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
236
|
+
def initialize_internals_callback
|
237
|
+
super
|
238
|
+
ensure_proper_type
|
239
|
+
end
|
226
240
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
241
|
+
# Sets the attribute used for single table inheritance to this class name if this is not the
|
242
|
+
# ActiveRecord::Base descendant.
|
243
|
+
# Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
|
244
|
+
# do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
|
245
|
+
# No such attribute would be set for objects of the Message class in that example.
|
246
|
+
def ensure_proper_type
|
247
|
+
klass = self.class
|
248
|
+
if klass.finder_needs_type_condition?
|
249
|
+
write_attribute(klass.inheritance_column, klass.sti_name)
|
250
|
+
end
|
236
251
|
end
|
237
|
-
end
|
238
252
|
end
|
239
253
|
end
|