activerecord 6.0.1 → 6.1.0
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 +4 -4
- data/CHANGELOG.md +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +36 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/relation.rb +108 -68
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +21 -70
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +26 -26
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -10,7 +10,6 @@ require "active_record/fixture_set/file"
|
|
10
10
|
require "active_record/fixture_set/render_context"
|
11
11
|
require "active_record/fixture_set/table_rows"
|
12
12
|
require "active_record/test_fixtures"
|
13
|
-
require "active_record/errors"
|
14
13
|
|
15
14
|
module ActiveRecord
|
16
15
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
@@ -41,7 +40,7 @@ module ActiveRecord
|
|
41
40
|
# separated by a blank line for your viewing pleasure.
|
42
41
|
#
|
43
42
|
# Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
|
44
|
-
# See
|
43
|
+
# See https://yaml.org/type/omap.html
|
45
44
|
# for the specification. You will need ordered fixtures when you have foreign key constraints
|
46
45
|
# on keys in the same table. This is commonly needed for tree structures. Example:
|
47
46
|
#
|
@@ -60,7 +59,7 @@ module ActiveRecord
|
|
60
59
|
# Since fixtures are a testing construct, we use them in our unit and functional tests. There
|
61
60
|
# are two ways to use the fixtures, but first let's take a look at a sample unit test:
|
62
61
|
#
|
63
|
-
# require
|
62
|
+
# require "test_helper"
|
64
63
|
#
|
65
64
|
# class WebSiteTest < ActiveSupport::TestCase
|
66
65
|
# test "web_site_count" do
|
@@ -182,7 +181,7 @@ module ActiveRecord
|
|
182
181
|
# end
|
183
182
|
# end
|
184
183
|
#
|
185
|
-
# If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
|
184
|
+
# If you preload your test database with all fixture data (probably by running `bin/rails db:fixtures:load`)
|
186
185
|
# and use transactional tests, then you may omit all fixtures declarations in your test cases since
|
187
186
|
# all the data's already there and every case rolls back its changes.
|
188
187
|
#
|
@@ -420,12 +419,35 @@ module ActiveRecord
|
|
420
419
|
#
|
421
420
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
422
421
|
#
|
422
|
+
# Besides using "DEFAULTS", you can also specify what fixtures will
|
423
|
+
# be ignored by setting "ignore" in "_fixture" section.
|
424
|
+
#
|
425
|
+
# # users.yml
|
426
|
+
# _fixture:
|
427
|
+
# ignore:
|
428
|
+
# - base
|
429
|
+
# # or use "ignore: base" when there is only one fixture needs to be ignored.
|
430
|
+
#
|
431
|
+
# base: &base
|
432
|
+
# admin: false
|
433
|
+
# introduction: "This is a default description"
|
434
|
+
#
|
435
|
+
# admin:
|
436
|
+
# <<: *base
|
437
|
+
# admin: true
|
438
|
+
#
|
439
|
+
# visitor:
|
440
|
+
# <<: *base
|
441
|
+
#
|
442
|
+
# In the above example, 'base' will be ignored when creating fixtures.
|
443
|
+
# This can be used for common attributes inheriting.
|
444
|
+
#
|
423
445
|
# == Configure the fixture model class
|
424
446
|
#
|
425
447
|
# It's possible to set the fixture's model class directly in the YAML file.
|
426
448
|
# This is helpful when fixtures are loaded outside tests and
|
427
449
|
# +set_fixture_class+ is not available (e.g.
|
428
|
-
# when running <tt>rails db:fixtures:load</tt>).
|
450
|
+
# when running <tt>bin/rails db:fixtures:load</tt>).
|
429
451
|
#
|
430
452
|
# _fixture:
|
431
453
|
# model_class: User
|
@@ -464,7 +486,6 @@ module ActiveRecord
|
|
464
486
|
end
|
465
487
|
|
466
488
|
private
|
467
|
-
|
468
489
|
def insert_class(class_names, name, klass)
|
469
490
|
# We only want to deal with AR objects.
|
470
491
|
if klass && klass < ActiveRecord::Base
|
@@ -564,13 +585,20 @@ module ActiveRecord
|
|
564
585
|
end
|
565
586
|
end
|
566
587
|
|
588
|
+
def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
|
589
|
+
identifier = identify(label, column_type)
|
590
|
+
model_name = default_fixture_model_name(fixture_set_name)
|
591
|
+
uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
|
592
|
+
|
593
|
+
SignedGlobalID.new(uri, **options)
|
594
|
+
end
|
595
|
+
|
567
596
|
# Superclass for the evaluation contexts used by ERB fixtures.
|
568
597
|
def context_class
|
569
598
|
@context_class ||= Class.new
|
570
599
|
end
|
571
600
|
|
572
601
|
private
|
573
|
-
|
574
602
|
def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
|
575
603
|
fixtures_map = {}
|
576
604
|
fixture_sets = fixture_files.map do |fixture_set_name|
|
@@ -621,7 +649,7 @@ module ActiveRecord
|
|
621
649
|
end
|
622
650
|
end
|
623
651
|
|
624
|
-
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
652
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
|
625
653
|
|
626
654
|
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
|
627
655
|
@name = name
|
@@ -654,8 +682,8 @@ module ActiveRecord
|
|
654
682
|
# Returns a hash of rows to be inserted. The key is the table, the value is
|
655
683
|
# a list of rows to insert to that table.
|
656
684
|
def table_rows
|
657
|
-
# allow
|
658
|
-
fixtures.
|
685
|
+
# allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
|
686
|
+
fixtures.except!(*ignored_fixtures)
|
659
687
|
|
660
688
|
TableRows.new(
|
661
689
|
table_name,
|
@@ -666,7 +694,6 @@ module ActiveRecord
|
|
666
694
|
end
|
667
695
|
|
668
696
|
private
|
669
|
-
|
670
697
|
def model_class=(class_name)
|
671
698
|
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
672
699
|
@model_class = class_name
|
@@ -675,6 +702,21 @@ module ActiveRecord
|
|
675
702
|
end
|
676
703
|
end
|
677
704
|
|
705
|
+
def ignored_fixtures=(base)
|
706
|
+
@ignored_fixtures =
|
707
|
+
case base
|
708
|
+
when Array
|
709
|
+
base
|
710
|
+
when String
|
711
|
+
[base]
|
712
|
+
else
|
713
|
+
[]
|
714
|
+
end
|
715
|
+
|
716
|
+
@ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
|
717
|
+
@ignored_fixtures.compact
|
718
|
+
end
|
719
|
+
|
678
720
|
# Loads the fixtures from the YAML file at +path+.
|
679
721
|
# If the file sets the +model_class+ and current instance value is not set,
|
680
722
|
# it uses the file value.
|
@@ -686,6 +728,7 @@ module ActiveRecord
|
|
686
728
|
yaml_files.each_with_object({}) do |file, fixtures|
|
687
729
|
FixtureSet::File.open(file) do |fh|
|
688
730
|
self.model_class ||= fh.model_class if fh.model_class
|
731
|
+
self.ignored_fixtures ||= fh.ignored_fixtures
|
689
732
|
fh.each do |fixture_name, row|
|
690
733
|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
691
734
|
end
|
@@ -38,6 +38,8 @@ module ActiveRecord
|
|
38
38
|
extend ActiveSupport::Concern
|
39
39
|
|
40
40
|
included do
|
41
|
+
class_attribute :store_full_class_name, instance_writer: false, default: true
|
42
|
+
|
41
43
|
# Determines whether to store the full constant name including namespace when using STI.
|
42
44
|
# This is true, by default.
|
43
45
|
class_attribute :store_full_sti_class, instance_writer: false, default: true
|
@@ -52,7 +54,7 @@ module ActiveRecord
|
|
52
54
|
raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
|
53
55
|
end
|
54
56
|
|
55
|
-
if
|
57
|
+
if _has_attribute?(inheritance_column)
|
56
58
|
subclass = subclass_from_attributes(attributes)
|
57
59
|
|
58
60
|
if subclass.nil? && scope_attributes = current_scope&.scope_for_create
|
@@ -162,12 +164,42 @@ module ActiveRecord
|
|
162
164
|
defined?(@abstract_class) && @abstract_class == true
|
163
165
|
end
|
164
166
|
|
167
|
+
# Returns the value to be stored in the inheritance column for STI.
|
165
168
|
def sti_name
|
166
|
-
store_full_sti_class ? name : name.demodulize
|
169
|
+
store_full_sti_class && store_full_class_name ? name : name.demodulize
|
167
170
|
end
|
168
171
|
|
172
|
+
# Returns the class for the provided +type_name+.
|
173
|
+
#
|
174
|
+
# It is used to find the class correspondent to the value stored in the inheritance column.
|
175
|
+
def sti_class_for(type_name)
|
176
|
+
if store_full_sti_class && store_full_class_name
|
177
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
178
|
+
else
|
179
|
+
compute_type(type_name)
|
180
|
+
end
|
181
|
+
rescue NameError
|
182
|
+
raise SubclassNotFound,
|
183
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
184
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
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
|
+
|
189
|
+
# Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
|
169
190
|
def polymorphic_name
|
170
|
-
base_class.name
|
191
|
+
store_full_class_name ? base_class.name : base_class.name.demodulize
|
192
|
+
end
|
193
|
+
|
194
|
+
# Returns the class for the provided +name+.
|
195
|
+
#
|
196
|
+
# It is used to find the class correspondent to the value stored in the polymorphic type column.
|
197
|
+
def polymorphic_class_for(name)
|
198
|
+
if store_full_class_name
|
199
|
+
ActiveSupport::Dependencies.constantize(name)
|
200
|
+
else
|
201
|
+
compute_type(name)
|
202
|
+
end
|
171
203
|
end
|
172
204
|
|
173
205
|
def inherited(subclass)
|
@@ -176,7 +208,6 @@ module ActiveRecord
|
|
176
208
|
end
|
177
209
|
|
178
210
|
protected
|
179
|
-
|
180
211
|
# Returns the class type of the record using the current module as a prefix. So descendants of
|
181
212
|
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
|
182
213
|
def compute_type(type_name)
|
@@ -208,7 +239,6 @@ module ActiveRecord
|
|
208
239
|
end
|
209
240
|
|
210
241
|
private
|
211
|
-
|
212
242
|
# Called by +instantiate+ to decide which class to use for a new
|
213
243
|
# record instance. For single-table inheritance, we check the record
|
214
244
|
# for a +type+ column and return the corresponding class.
|
@@ -221,32 +251,22 @@ module ActiveRecord
|
|
221
251
|
end
|
222
252
|
|
223
253
|
def using_single_table_inheritance?(record)
|
224
|
-
record[inheritance_column].present? &&
|
254
|
+
record[inheritance_column].present? && _has_attribute?(inheritance_column)
|
225
255
|
end
|
226
256
|
|
227
257
|
def find_sti_class(type_name)
|
228
258
|
type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
|
229
|
-
subclass =
|
230
|
-
|
231
|
-
ActiveSupport::Dependencies.constantize(type_name)
|
232
|
-
else
|
233
|
-
compute_type(type_name)
|
234
|
-
end
|
235
|
-
rescue NameError
|
236
|
-
raise SubclassNotFound,
|
237
|
-
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
238
|
-
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
239
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
240
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
241
|
-
end
|
259
|
+
subclass = sti_class_for(type_name)
|
260
|
+
|
242
261
|
unless subclass == self || descendants.include?(subclass)
|
243
262
|
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
244
263
|
end
|
264
|
+
|
245
265
|
subclass
|
246
266
|
end
|
247
267
|
|
248
268
|
def type_condition(table = arel_table)
|
249
|
-
sti_column =
|
269
|
+
sti_column = table[inheritance_column]
|
250
270
|
sti_names = ([self] + descendants).map(&:sti_name)
|
251
271
|
|
252
272
|
predicate_builder.build(sti_column, sti_names)
|
@@ -272,7 +292,6 @@ module ActiveRecord
|
|
272
292
|
end
|
273
293
|
|
274
294
|
private
|
275
|
-
|
276
295
|
def initialize_internals_callback
|
277
296
|
super
|
278
297
|
ensure_proper_type
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
class InsertAll # :nodoc:
|
5
7
|
attr_reader :model, :connection, :inserts, :keys
|
@@ -8,13 +10,19 @@ module ActiveRecord
|
|
8
10
|
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
|
9
11
|
raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
|
10
12
|
|
11
|
-
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
|
13
|
+
@model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
|
12
14
|
@on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
|
13
15
|
|
16
|
+
if model.scope_attributes?
|
17
|
+
@scope_attributes = model.scope_attributes
|
18
|
+
@keys |= @scope_attributes.keys
|
19
|
+
end
|
20
|
+
@keys = @keys.to_set
|
21
|
+
|
14
22
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
15
23
|
@returning = false if @returning == []
|
16
24
|
|
17
|
-
@unique_by = find_unique_index_for(unique_by)
|
25
|
+
@unique_by = find_unique_index_for(unique_by)
|
18
26
|
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
19
27
|
|
20
28
|
ensure_valid_options_for_connection!
|
@@ -32,7 +40,7 @@ module ActiveRecord
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def primary_keys
|
35
|
-
Array(model.
|
43
|
+
Array(connection.schema_cache.primary_keys(model.table_name))
|
36
44
|
end
|
37
45
|
|
38
46
|
|
@@ -47,6 +55,8 @@ module ActiveRecord
|
|
47
55
|
def map_key_with_value
|
48
56
|
inserts.map do |attributes|
|
49
57
|
attributes = attributes.stringify_keys
|
58
|
+
attributes.merge!(scope_attributes) if scope_attributes
|
59
|
+
|
50
60
|
verify_attributes(attributes)
|
51
61
|
|
52
62
|
keys.map do |key|
|
@@ -56,13 +66,20 @@ module ActiveRecord
|
|
56
66
|
end
|
57
67
|
|
58
68
|
private
|
69
|
+
attr_reader :scope_attributes
|
70
|
+
|
59
71
|
def find_unique_index_for(unique_by)
|
60
|
-
|
72
|
+
return unique_by if !connection.supports_insert_conflict_target?
|
73
|
+
|
74
|
+
name_or_columns = unique_by || model.primary_key
|
75
|
+
match = Array(name_or_columns).map(&:to_s)
|
61
76
|
|
62
77
|
if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
|
63
78
|
index
|
79
|
+
elsif match == primary_keys
|
80
|
+
unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
|
64
81
|
else
|
65
|
-
raise ArgumentError, "No unique index found for #{
|
82
|
+
raise ArgumentError, "No unique index found for #{name_or_columns}"
|
66
83
|
end
|
67
84
|
end
|
68
85
|
|
@@ -120,7 +137,7 @@ module ActiveRecord
|
|
120
137
|
end
|
121
138
|
|
122
139
|
def into
|
123
|
-
"INTO #{model.quoted_table_name}(#{columns_list})"
|
140
|
+
"INTO #{model.quoted_table_name} (#{columns_list})"
|
124
141
|
end
|
125
142
|
|
126
143
|
def values_list
|
@@ -130,7 +147,7 @@ module ActiveRecord
|
|
130
147
|
connection.with_yaml_fallback(types[key].serialize(value))
|
131
148
|
end
|
132
149
|
|
133
|
-
Arel::
|
150
|
+
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
|
134
151
|
end
|
135
152
|
|
136
153
|
def returning
|
@@ -151,9 +168,21 @@ module ActiveRecord
|
|
151
168
|
quote_columns(insert_all.updatable_columns)
|
152
169
|
end
|
153
170
|
|
171
|
+
def touch_model_timestamps_unless(&block)
|
172
|
+
model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
|
173
|
+
if touch_timestamp_attribute?(column_name)
|
174
|
+
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
|
175
|
+
end
|
176
|
+
end.compact.join
|
177
|
+
end
|
178
|
+
|
154
179
|
private
|
155
180
|
attr_reader :connection, :insert_all
|
156
181
|
|
182
|
+
def touch_timestamp_attribute?(column_name)
|
183
|
+
update_duplicates? && !insert_all.updatable_columns.include?(column_name)
|
184
|
+
end
|
185
|
+
|
157
186
|
def columns_list
|
158
187
|
format_columns(insert_all.keys)
|
159
188
|
end
|
@@ -164,11 +193,11 @@ module ActiveRecord
|
|
164
193
|
unknown_column = (keys - columns.keys).first
|
165
194
|
raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column
|
166
195
|
|
167
|
-
keys.
|
196
|
+
keys.index_with { |key| model.type_for_attribute(key) }
|
168
197
|
end
|
169
198
|
|
170
199
|
def format_columns(columns)
|
171
|
-
quote_columns(columns).join(",")
|
200
|
+
columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
|
172
201
|
end
|
173
202
|
|
174
203
|
def quote_columns(columns)
|
@@ -93,7 +93,7 @@ module ActiveRecord
|
|
93
93
|
# cache_version, but this method can be overwritten to return something else.
|
94
94
|
#
|
95
95
|
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
|
96
|
-
# +false
|
96
|
+
# +false+.
|
97
97
|
def cache_version
|
98
98
|
return unless cache_versioning
|
99
99
|
|
@@ -104,10 +104,8 @@ module ActiveRecord
|
|
104
104
|
elsif timestamp = updated_at
|
105
105
|
timestamp.utc.to_s(cache_timestamp_format)
|
106
106
|
end
|
107
|
-
|
108
|
-
|
109
|
-
raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
|
110
|
-
end
|
107
|
+
elsif self.class.has_attribute?("updated_at")
|
108
|
+
raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
|
111
109
|
end
|
112
110
|
end
|
113
111
|
|
@@ -6,8 +6,15 @@ require "active_record/scoping/named"
|
|
6
6
|
module ActiveRecord
|
7
7
|
# This class is used to create a table that keeps track of values and keys such
|
8
8
|
# as which environment migrations were run in.
|
9
|
+
#
|
10
|
+
# This is enabled by default. To disable this functionality set
|
11
|
+
# `use_metadata_table` to false in your database configuration.
|
9
12
|
class InternalMetadata < ActiveRecord::Base # :nodoc:
|
10
13
|
class << self
|
14
|
+
def enabled?
|
15
|
+
ActiveRecord::Base.connection.use_metadata_table?
|
16
|
+
end
|
17
|
+
|
11
18
|
def _internal?
|
12
19
|
true
|
13
20
|
end
|
@@ -21,24 +28,24 @@ module ActiveRecord
|
|
21
28
|
end
|
22
29
|
|
23
30
|
def []=(key, value)
|
31
|
+
return unless enabled?
|
32
|
+
|
24
33
|
find_or_initialize_by(key: key).update!(value: value)
|
25
34
|
end
|
26
35
|
|
27
36
|
def [](key)
|
28
|
-
|
29
|
-
end
|
37
|
+
return unless enabled?
|
30
38
|
|
31
|
-
|
32
|
-
connection.table_exists?(table_name)
|
39
|
+
where(key: key).pluck(:value).first
|
33
40
|
end
|
34
41
|
|
35
42
|
# Creates an internal metadata table with columns +key+ and +value+
|
36
43
|
def create_table
|
37
|
-
unless
|
38
|
-
key_options = connection.internal_string_options_for_primary_key
|
44
|
+
return unless enabled?
|
39
45
|
|
46
|
+
unless connection.table_exists?(table_name)
|
40
47
|
connection.create_table(table_name, id: false) do |t|
|
41
|
-
t.string :key,
|
48
|
+
t.string :key, **connection.internal_string_options_for_primary_key
|
42
49
|
t.string :value
|
43
50
|
t.timestamps
|
44
51
|
end
|
@@ -46,6 +53,8 @@ module ActiveRecord
|
|
46
53
|
end
|
47
54
|
|
48
55
|
def drop_table
|
56
|
+
return unless enabled?
|
57
|
+
|
49
58
|
connection.drop_table table_name, if_exists: true
|
50
59
|
end
|
51
60
|
end
|
@@ -1,13 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
module LegacyYamlAdapter
|
4
|
+
module LegacyYamlAdapter # :nodoc:
|
5
5
|
def self.convert(klass, coder)
|
6
6
|
return coder unless coder.is_a?(Psych::Coder)
|
7
7
|
|
8
8
|
case coder["active_record_yaml_version"]
|
9
9
|
when 1, 2 then coder
|
10
10
|
else
|
11
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
12
|
+
YAML loading from legacy format older than Rails 5.0 is deprecated
|
13
|
+
and will be removed in Rails 6.2.
|
14
|
+
MSG
|
11
15
|
if coder["attributes"].is_a?(ActiveModel::AttributeSet)
|
12
16
|
Rails420.convert(klass, coder)
|
13
17
|
else
|
@@ -16,7 +20,7 @@ module ActiveRecord
|
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
|
-
module Rails420
|
23
|
+
module Rails420 # :nodoc:
|
20
24
|
def self.convert(klass, coder)
|
21
25
|
attribute_set = coder["attributes"]
|
22
26
|
|
@@ -32,7 +36,7 @@ module ActiveRecord
|
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
|
-
module Rails41
|
39
|
+
module Rails41 # :nodoc:
|
36
40
|
def self.convert(klass, coder)
|
37
41
|
attributes = klass.attributes_builder
|
38
42
|
.build_from_database(coder["attributes"])
|
@@ -60,6 +60,15 @@ module ActiveRecord
|
|
60
60
|
self.class.locking_enabled?
|
61
61
|
end
|
62
62
|
|
63
|
+
def increment!(*, **) #:nodoc:
|
64
|
+
super.tap do
|
65
|
+
if locking_enabled?
|
66
|
+
self[self.class.locking_column] += 1
|
67
|
+
clear_attribute_change(self.class.locking_column)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
63
72
|
private
|
64
73
|
def _create_record(attribute_names = self.attribute_names)
|
65
74
|
if locking_enabled?
|
@@ -80,7 +89,8 @@ module ActiveRecord
|
|
80
89
|
|
81
90
|
begin
|
82
91
|
locking_column = self.class.locking_column
|
83
|
-
previous_lock_value =
|
92
|
+
previous_lock_value = attribute_before_type_cast(locking_column)
|
93
|
+
attribute_names = attribute_names.dup if attribute_names.frozen?
|
84
94
|
attribute_names << locking_column
|
85
95
|
|
86
96
|
self[locking_column] += 1
|
@@ -88,7 +98,7 @@ module ActiveRecord
|
|
88
98
|
affected_rows = self.class._update_record(
|
89
99
|
attributes_with_values(attribute_names),
|
90
100
|
@primary_key => id_in_database,
|
91
|
-
locking_column =>
|
101
|
+
locking_column => @attributes[locking_column].original_value_for_database
|
92
102
|
)
|
93
103
|
|
94
104
|
if affected_rows != 1
|
@@ -111,7 +121,7 @@ module ActiveRecord
|
|
111
121
|
|
112
122
|
affected_rows = self.class._delete_record(
|
113
123
|
@primary_key => id_in_database,
|
114
|
-
locking_column =>
|
124
|
+
locking_column => attribute_before_type_cast(locking_column)
|
115
125
|
)
|
116
126
|
|
117
127
|
if affected_rows != 1
|
@@ -155,21 +165,12 @@ module ActiveRecord
|
|
155
165
|
super
|
156
166
|
end
|
157
167
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
162
|
-
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
163
|
-
# `locking_column` would not be picked up.
|
164
|
-
def inherited(subclass)
|
165
|
-
subclass.class_eval do
|
166
|
-
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
167
|
-
decorate_matching_attribute_types(is_lock_column, "_optimistic_locking") do |type|
|
168
|
-
LockingType.new(type)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
super
|
168
|
+
def define_attribute(name, cast_type, **) # :nodoc:
|
169
|
+
if lock_optimistically && name == locking_column
|
170
|
+
cast_type = LockingType.new(cast_type)
|
172
171
|
end
|
172
|
+
super
|
173
|
+
end
|
173
174
|
end
|
174
175
|
end
|
175
176
|
|
@@ -177,6 +178,10 @@ module ActiveRecord
|
|
177
178
|
# `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
|
178
179
|
# during update record.
|
179
180
|
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
181
|
+
def self.new(subtype)
|
182
|
+
self === subtype ? subtype : super
|
183
|
+
end
|
184
|
+
|
180
185
|
def deserialize(value)
|
181
186
|
super.to_i
|
182
187
|
end
|
@@ -53,8 +53,12 @@ module ActiveRecord
|
|
53
53
|
# end
|
54
54
|
#
|
55
55
|
# Database-specific information on row locking:
|
56
|
-
#
|
57
|
-
#
|
56
|
+
#
|
57
|
+
# [MySQL]
|
58
|
+
# https://dev.mysql.com/doc/refman/en/innodb-locking-reads.html
|
59
|
+
#
|
60
|
+
# [PostgreSQL]
|
61
|
+
# https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
|
58
62
|
module Pessimistic
|
59
63
|
# Obtain a row lock on this record. Reloads the record to obtain the requested
|
60
64
|
# lock. Pass an SQL locking clause to append the end of the SELECT statement
|