activerecord 6.0.6 → 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 +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -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 -1
- 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 +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- 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 +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- 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 +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- 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/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- 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 +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- 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 +12 -53
- 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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- 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 +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- 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 +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- 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 -40
- 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/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- 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 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- 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 +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- 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 +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- 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/named.rb +1 -17
- 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 +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- 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 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- 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 +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- 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 +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- 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 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
@@ -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
|
@@ -563,6 +585,14 @@ module ActiveRecord
|
|
563
585
|
end
|
564
586
|
end
|
565
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
|
+
|
566
596
|
# Superclass for the evaluation contexts used by ERB fixtures.
|
567
597
|
def context_class
|
568
598
|
@context_class ||= Class.new
|
@@ -619,7 +649,7 @@ module ActiveRecord
|
|
619
649
|
end
|
620
650
|
end
|
621
651
|
|
622
|
-
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
652
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
|
623
653
|
|
624
654
|
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
|
625
655
|
@name = name
|
@@ -652,8 +682,8 @@ module ActiveRecord
|
|
652
682
|
# Returns a hash of rows to be inserted. The key is the table, the value is
|
653
683
|
# a list of rows to insert to that table.
|
654
684
|
def table_rows
|
655
|
-
# allow
|
656
|
-
fixtures.
|
685
|
+
# allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
|
686
|
+
fixtures.except!(*ignored_fixtures)
|
657
687
|
|
658
688
|
TableRows.new(
|
659
689
|
table_name,
|
@@ -672,6 +702,21 @@ module ActiveRecord
|
|
672
702
|
end
|
673
703
|
end
|
674
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
|
+
|
675
720
|
# Loads the fixtures from the YAML file at +path+.
|
676
721
|
# If the file sets the +model_class+ and current instance value is not set,
|
677
722
|
# it uses the file value.
|
@@ -683,6 +728,7 @@ module ActiveRecord
|
|
683
728
|
yaml_files.each_with_object({}) do |file, fixtures|
|
684
729
|
FixtureSet::File.open(file) do |fh|
|
685
730
|
self.model_class ||= fh.model_class if fh.model_class
|
731
|
+
self.ignored_fixtures ||= fh.ignored_fixtures
|
686
732
|
fh.each do |fixture_name, row|
|
687
733
|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
688
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
|
170
|
+
end
|
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."
|
167
187
|
end
|
168
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)
|
@@ -219,32 +251,22 @@ module ActiveRecord
|
|
219
251
|
end
|
220
252
|
|
221
253
|
def using_single_table_inheritance?(record)
|
222
|
-
record[inheritance_column].present? &&
|
254
|
+
record[inheritance_column].present? && _has_attribute?(inheritance_column)
|
223
255
|
end
|
224
256
|
|
225
257
|
def find_sti_class(type_name)
|
226
258
|
type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
|
227
|
-
subclass =
|
228
|
-
|
229
|
-
ActiveSupport::Dependencies.constantize(type_name)
|
230
|
-
else
|
231
|
-
compute_type(type_name)
|
232
|
-
end
|
233
|
-
rescue NameError
|
234
|
-
raise SubclassNotFound,
|
235
|
-
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
236
|
-
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
237
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
238
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
239
|
-
end
|
259
|
+
subclass = sti_class_for(type_name)
|
260
|
+
|
240
261
|
unless subclass == self || descendants.include?(subclass)
|
241
262
|
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
242
263
|
end
|
264
|
+
|
243
265
|
subclass
|
244
266
|
end
|
245
267
|
|
246
268
|
def type_condition(table = arel_table)
|
247
|
-
sti_column =
|
269
|
+
sti_column = table[inheritance_column]
|
248
270
|
sti_names = ([self] + descendants).map(&:sti_name)
|
249
271
|
|
250
272
|
predicate_builder.build(sti_column, sti_names)
|
@@ -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
|
|
@@ -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
|
@@ -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"])
|
@@ -89,7 +89,8 @@ module ActiveRecord
|
|
89
89
|
|
90
90
|
begin
|
91
91
|
locking_column = self.class.locking_column
|
92
|
-
previous_lock_value =
|
92
|
+
previous_lock_value = attribute_before_type_cast(locking_column)
|
93
|
+
attribute_names = attribute_names.dup if attribute_names.frozen?
|
93
94
|
attribute_names << locking_column
|
94
95
|
|
95
96
|
self[locking_column] += 1
|
@@ -97,7 +98,7 @@ module ActiveRecord
|
|
97
98
|
affected_rows = self.class._update_record(
|
98
99
|
attributes_with_values(attribute_names),
|
99
100
|
@primary_key => id_in_database,
|
100
|
-
locking_column =>
|
101
|
+
locking_column => @attributes[locking_column].original_value_for_database
|
101
102
|
)
|
102
103
|
|
103
104
|
if affected_rows != 1
|
@@ -120,7 +121,7 @@ module ActiveRecord
|
|
120
121
|
|
121
122
|
affected_rows = self.class._delete_record(
|
122
123
|
@primary_key => id_in_database,
|
123
|
-
locking_column =>
|
124
|
+
locking_column => attribute_before_type_cast(locking_column)
|
124
125
|
)
|
125
126
|
|
126
127
|
if affected_rows != 1
|
@@ -164,20 +165,12 @@ module ActiveRecord
|
|
164
165
|
super
|
165
166
|
end
|
166
167
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
171
|
-
# `locking_column` would not be picked up.
|
172
|
-
def inherited(subclass)
|
173
|
-
subclass.class_eval do
|
174
|
-
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
175
|
-
decorate_matching_attribute_types(is_lock_column, "_optimistic_locking") do |type|
|
176
|
-
LockingType.new(type)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
super
|
168
|
+
def define_attribute(name, cast_type, **) # :nodoc:
|
169
|
+
if lock_optimistically && name == locking_column
|
170
|
+
cast_type = LockingType.new(cast_type)
|
180
171
|
end
|
172
|
+
super
|
173
|
+
end
|
181
174
|
end
|
182
175
|
end
|
183
176
|
|
@@ -185,6 +178,10 @@ module ActiveRecord
|
|
185
178
|
# `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
|
186
179
|
# during update record.
|
187
180
|
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
181
|
+
def self.new(subtype)
|
182
|
+
self === subtype ? subtype : super
|
183
|
+
end
|
184
|
+
|
188
185
|
def deserialize(value)
|
189
186
|
super.to_i
|
190
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
|
@@ -19,6 +19,15 @@ module ActiveRecord
|
|
19
19
|
rt
|
20
20
|
end
|
21
21
|
|
22
|
+
def strict_loading_violation(event)
|
23
|
+
debug do
|
24
|
+
owner = event.payload[:owner]
|
25
|
+
association = event.payload[:association]
|
26
|
+
|
27
|
+
color("Strict loading violation: #{association} lazily loaded on #{owner}.", RED)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
22
31
|
def sql(event)
|
23
32
|
self.class.runtime += event.duration
|
24
33
|
return unless logger.debug?
|
@@ -32,11 +41,15 @@ module ActiveRecord
|
|
32
41
|
sql = payload[:sql]
|
33
42
|
binds = nil
|
34
43
|
|
35
|
-
|
44
|
+
if payload[:binds]&.any?
|
36
45
|
casted_params = type_casted_binds(payload[:type_casted_binds])
|
37
|
-
|
38
|
-
|
39
|
-
|
46
|
+
|
47
|
+
binds = []
|
48
|
+
payload[:binds].each_with_index do |attr, i|
|
49
|
+
binds << render_bind(attr, casted_params[i])
|
50
|
+
end
|
51
|
+
binds = binds.inspect
|
52
|
+
binds.prepend(" ")
|
40
53
|
end
|
41
54
|
|
42
55
|
name = colorize_payload_name(name, payload[:name])
|
@@ -51,13 +64,18 @@ module ActiveRecord
|
|
51
64
|
end
|
52
65
|
|
53
66
|
def render_bind(attr, value)
|
54
|
-
|
67
|
+
case attr
|
68
|
+
when ActiveModel::Attribute
|
69
|
+
if attr.type.binary? && attr.value
|
70
|
+
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
71
|
+
end
|
72
|
+
when Array
|
55
73
|
attr = attr.first
|
56
|
-
|
57
|
-
|
74
|
+
else
|
75
|
+
attr = nil
|
58
76
|
end
|
59
77
|
|
60
|
-
[attr
|
78
|
+
[attr&.name, value]
|
61
79
|
end
|
62
80
|
|
63
81
|
def colorize_payload_name(name, payload_name)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record/middleware/database_selector/resolver/session"
|
4
|
+
require "active_support/core_ext/numeric/time"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Middleware
|
@@ -43,6 +44,10 @@ module ActiveRecord
|
|
43
44
|
write_to_primary(&blk)
|
44
45
|
end
|
45
46
|
|
47
|
+
def update_context(response)
|
48
|
+
context.save(response)
|
49
|
+
end
|
50
|
+
|
46
51
|
private
|
47
52
|
def read_from_primary(&blk)
|
48
53
|
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
|
@@ -59,11 +59,14 @@ module ActiveRecord
|
|
59
59
|
context = context_klass.call(request)
|
60
60
|
resolver = resolver_klass.call(context, options)
|
61
61
|
|
62
|
-
if reading_request?(request)
|
62
|
+
response = if reading_request?(request)
|
63
63
|
resolver.read(&blk)
|
64
64
|
else
|
65
65
|
resolver.write(&blk)
|
66
66
|
end
|
67
|
+
|
68
|
+
resolver.update_context(response)
|
69
|
+
response
|
67
70
|
end
|
68
71
|
|
69
72
|
def reading_request?(request)
|