activerecord 6.1.6 → 7.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1627 -983
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +50 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +35 -31
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -16
- data/lib/active_record/associations/preloader/association.rb +207 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +439 -305
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +25 -10
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +10 -13
- data/lib/active_record/attribute_methods.rb +121 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +61 -30
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -34
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -138
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -149
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +394 -74
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +509 -247
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +107 -136
- data/lib/active_record/core.rb +202 -223
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +84 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +61 -15
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +224 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +96 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +171 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +131 -86
- data/lib/active_record/future_result.rb +164 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +221 -48
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +358 -171
- data/lib/active_record/model_schema.rb +120 -101
- data/lib/active_record/nested_attributes.rb +37 -18
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +405 -85
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +219 -43
- data/lib/active_record/railties/controller_runtime.rb +13 -9
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +241 -80
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +219 -90
- data/lib/active_record/relation/delegation.rb +27 -13
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +654 -127
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +262 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +18 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +16 -11
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +225 -136
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +123 -99
- data/lib/active_record/timestamp.rb +29 -18
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +139 -19
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +93 -13
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/inflector"
|
3
4
|
require "active_support/core_ext/hash/indifferent_access"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
|
-
#
|
7
|
+
# = Single table inheritance
|
7
8
|
#
|
8
9
|
# Active Record allows inheritance by storing the name of the class in a column that by
|
9
10
|
# default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
|
@@ -31,8 +32,9 @@ module ActiveRecord
|
|
31
32
|
# be triggered. In that case, it'll work just like normal subclasses with no special magic
|
32
33
|
# for differentiating between them or reloading the right type with find.
|
33
34
|
#
|
34
|
-
# Note, all the attributes for all the cases are kept in the same table.
|
35
|
-
#
|
35
|
+
# Note, all the attributes for all the cases are kept in the same table.
|
36
|
+
# Read more:
|
37
|
+
# * https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
|
36
38
|
#
|
37
39
|
module Inheritance
|
38
40
|
extend ActiveSupport::Concern
|
@@ -43,6 +45,8 @@ module ActiveRecord
|
|
43
45
|
# Determines whether to store the full constant name including namespace when using STI.
|
44
46
|
# This is true, by default.
|
45
47
|
class_attribute :store_full_sti_class, instance_writer: false, default: true
|
48
|
+
|
49
|
+
set_base_class
|
46
50
|
end
|
47
51
|
|
48
52
|
module ClassMethods
|
@@ -85,30 +89,30 @@ module ActiveRecord
|
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
88
|
-
def finder_needs_type_condition?
|
92
|
+
def finder_needs_type_condition? # :nodoc:
|
89
93
|
# This is like this because benchmarking justifies the strange :false stuff
|
90
94
|
:true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
|
91
95
|
end
|
92
96
|
|
93
|
-
# Returns the class
|
94
|
-
#
|
97
|
+
# Returns the first class in the inheritance hierarchy that descends from either an
|
98
|
+
# abstract class or from <tt>ActiveRecord::Base</tt>.
|
95
99
|
#
|
96
|
-
#
|
97
|
-
# through some arbitrarily deep hierarchy, B.base_class will return A.
|
100
|
+
# Consider the following behaviour:
|
98
101
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
102
|
+
# class ApplicationRecord < ActiveRecord::Base
|
103
|
+
# self.abstract_class = true
|
104
|
+
# end
|
105
|
+
# class Shape < ApplicationRecord
|
106
|
+
# self.abstract_class = true
|
107
|
+
# end
|
108
|
+
# Polygon = Class.new(Shape)
|
109
|
+
# Square = Class.new(Polygon)
|
110
|
+
#
|
111
|
+
# ApplicationRecord.base_class # => ApplicationRecord
|
112
|
+
# Shape.base_class # => Shape
|
113
|
+
# Polygon.base_class # => Polygon
|
114
|
+
# Square.base_class # => Polygon
|
115
|
+
attr_reader :base_class
|
112
116
|
|
113
117
|
# Returns whether the class is a base class.
|
114
118
|
# See #base_class for more information.
|
@@ -123,7 +127,7 @@ module ActiveRecord
|
|
123
127
|
# true.
|
124
128
|
# +ApplicationRecord+, for example, is generated as an abstract class.
|
125
129
|
#
|
126
|
-
# Consider the following default
|
130
|
+
# Consider the following default behavior:
|
127
131
|
#
|
128
132
|
# Shape = Class.new(ActiveRecord::Base)
|
129
133
|
# Polygon = Class.new(Shape)
|
@@ -164,6 +168,21 @@ module ActiveRecord
|
|
164
168
|
defined?(@abstract_class) && @abstract_class == true
|
165
169
|
end
|
166
170
|
|
171
|
+
# Sets the application record class for Active Record
|
172
|
+
#
|
173
|
+
# This is useful if your application uses a different class than
|
174
|
+
# ApplicationRecord for your primary abstract class. This class
|
175
|
+
# will share a database connection with Active Record. It is the class
|
176
|
+
# that connects to your primary database.
|
177
|
+
def primary_abstract_class
|
178
|
+
if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
|
179
|
+
raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
|
180
|
+
end
|
181
|
+
|
182
|
+
self.abstract_class = true
|
183
|
+
ActiveRecord.application_record_class = self
|
184
|
+
end
|
185
|
+
|
167
186
|
# Returns the value to be stored in the inheritance column for STI.
|
168
187
|
def sti_name
|
169
188
|
store_full_sti_class && store_full_class_name ? name : name.demodulize
|
@@ -174,7 +193,7 @@ module ActiveRecord
|
|
174
193
|
# It is used to find the class correspondent to the value stored in the inheritance column.
|
175
194
|
def sti_class_for(type_name)
|
176
195
|
if store_full_sti_class && store_full_class_name
|
177
|
-
|
196
|
+
type_name.constantize
|
178
197
|
else
|
179
198
|
compute_type(type_name)
|
180
199
|
end
|
@@ -196,15 +215,23 @@ module ActiveRecord
|
|
196
215
|
# It is used to find the class correspondent to the value stored in the polymorphic type column.
|
197
216
|
def polymorphic_class_for(name)
|
198
217
|
if store_full_class_name
|
199
|
-
|
218
|
+
name.constantize
|
200
219
|
else
|
201
220
|
compute_type(name)
|
202
221
|
end
|
203
222
|
end
|
204
223
|
|
205
|
-
def
|
206
|
-
|
224
|
+
def dup # :nodoc:
|
225
|
+
# `initialize_dup` / `initialize_copy` don't work when defined
|
226
|
+
# in the `singleton_class`.
|
227
|
+
other = super
|
228
|
+
other.set_base_class
|
229
|
+
other
|
230
|
+
end
|
231
|
+
|
232
|
+
def initialize_clone(other) # :nodoc:
|
207
233
|
super
|
234
|
+
set_base_class
|
208
235
|
end
|
209
236
|
|
210
237
|
protected
|
@@ -214,10 +241,10 @@ module ActiveRecord
|
|
214
241
|
if type_name.start_with?("::")
|
215
242
|
# If the type is prefixed with a scope operator then we assume that
|
216
243
|
# the type_name is an absolute reference.
|
217
|
-
|
244
|
+
type_name.constantize
|
218
245
|
else
|
219
246
|
type_candidate = @_type_candidates_cache[type_name]
|
220
|
-
if type_candidate && type_constant =
|
247
|
+
if type_candidate && type_constant = type_candidate.safe_constantize
|
221
248
|
return type_constant
|
222
249
|
end
|
223
250
|
|
@@ -227,7 +254,7 @@ module ActiveRecord
|
|
227
254
|
candidates << type_name
|
228
255
|
|
229
256
|
candidates.each do |candidate|
|
230
|
-
constant =
|
257
|
+
constant = candidate.safe_constantize
|
231
258
|
if candidate == constant.to_s
|
232
259
|
@_type_candidates_cache[type_name] = candidate
|
233
260
|
return constant
|
@@ -238,7 +265,32 @@ module ActiveRecord
|
|
238
265
|
end
|
239
266
|
end
|
240
267
|
|
268
|
+
def set_base_class # :nodoc:
|
269
|
+
@base_class = if self == Base
|
270
|
+
self
|
271
|
+
else
|
272
|
+
unless self < Base
|
273
|
+
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
|
274
|
+
end
|
275
|
+
|
276
|
+
if superclass == Base || superclass.abstract_class?
|
277
|
+
self
|
278
|
+
else
|
279
|
+
superclass.base_class
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
241
284
|
private
|
285
|
+
def inherited(subclass)
|
286
|
+
super
|
287
|
+
subclass.set_base_class
|
288
|
+
subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
|
289
|
+
subclass.class_eval do
|
290
|
+
@finder_needs_type_condition = nil
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
242
294
|
# Called by +instantiate+ to decide which class to use for a new
|
243
295
|
# record instance. For single-table inheritance, we check the record
|
244
296
|
# for a +type+ column and return the corresponding class.
|
@@ -5,13 +5,23 @@ require "active_support/core_ext/enumerable"
|
|
5
5
|
module ActiveRecord
|
6
6
|
class InsertAll # :nodoc:
|
7
7
|
attr_reader :model, :connection, :inserts, :keys
|
8
|
-
attr_reader :on_duplicate, :returning, :unique_by
|
9
|
-
|
10
|
-
def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
|
11
|
-
|
12
|
-
|
13
|
-
@
|
14
|
-
|
8
|
+
attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
|
9
|
+
|
10
|
+
def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
|
11
|
+
@model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
|
12
|
+
@on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
|
13
|
+
@record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
|
14
|
+
|
15
|
+
disallow_raw_sql!(on_duplicate)
|
16
|
+
disallow_raw_sql!(returning)
|
17
|
+
|
18
|
+
if @inserts.empty?
|
19
|
+
@keys = []
|
20
|
+
else
|
21
|
+
resolve_sti
|
22
|
+
resolve_attribute_aliases
|
23
|
+
@keys = @inserts.first.keys
|
24
|
+
end
|
15
25
|
|
16
26
|
if model.scope_attributes?
|
17
27
|
@scope_attributes = model.scope_attributes
|
@@ -22,13 +32,15 @@ module ActiveRecord
|
|
22
32
|
@returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
|
23
33
|
@returning = false if @returning == []
|
24
34
|
|
25
|
-
@unique_by = find_unique_index_for(unique_by)
|
26
|
-
@on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
|
35
|
+
@unique_by = find_unique_index_for(@unique_by)
|
27
36
|
|
37
|
+
configure_on_duplicate_update_logic
|
28
38
|
ensure_valid_options_for_connection!
|
29
39
|
end
|
30
40
|
|
31
41
|
def execute
|
42
|
+
return ActiveRecord::Result.empty if inserts.empty?
|
43
|
+
|
32
44
|
message = +"#{model} "
|
33
45
|
message << "Bulk " if inserts.many?
|
34
46
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
@@ -36,7 +48,7 @@ module ActiveRecord
|
|
36
48
|
end
|
37
49
|
|
38
50
|
def updatable_columns
|
39
|
-
keys - readonly_columns - unique_by_columns
|
51
|
+
@updatable_columns ||= keys - readonly_columns - unique_by_columns
|
40
52
|
end
|
41
53
|
|
42
54
|
def primary_keys
|
@@ -56,18 +68,80 @@ module ActiveRecord
|
|
56
68
|
inserts.map do |attributes|
|
57
69
|
attributes = attributes.stringify_keys
|
58
70
|
attributes.merge!(scope_attributes) if scope_attributes
|
71
|
+
attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
|
59
72
|
|
60
73
|
verify_attributes(attributes)
|
61
74
|
|
62
|
-
|
75
|
+
keys_including_timestamps.map do |key|
|
63
76
|
yield key, attributes[key]
|
64
77
|
end
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
81
|
+
def record_timestamps?
|
82
|
+
@record_timestamps
|
83
|
+
end
|
84
|
+
|
85
|
+
# TODO: Consider renaming this method, as it only conditionally extends keys, not always
|
86
|
+
def keys_including_timestamps
|
87
|
+
@keys_including_timestamps ||= if record_timestamps?
|
88
|
+
keys + model.all_timestamp_attributes_in_model
|
89
|
+
else
|
90
|
+
keys
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
68
94
|
private
|
69
95
|
attr_reader :scope_attributes
|
70
96
|
|
97
|
+
def has_attribute_aliases?(attributes)
|
98
|
+
attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def resolve_sti
|
102
|
+
return if model.descends_from_active_record?
|
103
|
+
|
104
|
+
sti_type = model.sti_name
|
105
|
+
@inserts = @inserts.map do |insert|
|
106
|
+
insert.reverse_merge(model.inheritance_column.to_s => sti_type)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def resolve_attribute_aliases
|
111
|
+
return unless has_attribute_aliases?(@inserts.first)
|
112
|
+
|
113
|
+
@inserts = @inserts.map do |insert|
|
114
|
+
insert.transform_keys { |attribute| resolve_attribute_alias(attribute) }
|
115
|
+
end
|
116
|
+
|
117
|
+
@update_only = Array(@update_only).map { |attribute| resolve_attribute_alias(attribute) } if @update_only
|
118
|
+
@unique_by = Array(@unique_by).map { |attribute| resolve_attribute_alias(attribute) } if @unique_by
|
119
|
+
end
|
120
|
+
|
121
|
+
def resolve_attribute_alias(attribute)
|
122
|
+
model.attribute_alias(attribute) || attribute
|
123
|
+
end
|
124
|
+
|
125
|
+
def configure_on_duplicate_update_logic
|
126
|
+
if custom_update_sql_provided? && update_only.present?
|
127
|
+
raise ArgumentError, "You can't set :update_only and provide custom update SQL via :on_duplicate at the same time"
|
128
|
+
end
|
129
|
+
|
130
|
+
if update_only.present?
|
131
|
+
@updatable_columns = Array(update_only)
|
132
|
+
@on_duplicate = :update
|
133
|
+
elsif custom_update_sql_provided?
|
134
|
+
@update_sql = on_duplicate
|
135
|
+
@on_duplicate = :update
|
136
|
+
elsif @on_duplicate == :update && updatable_columns.empty?
|
137
|
+
@on_duplicate = :skip
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def custom_update_sql_provided?
|
142
|
+
@custom_update_sql_provided ||= Arel.arel_node?(on_duplicate)
|
143
|
+
end
|
144
|
+
|
71
145
|
def find_unique_index_for(unique_by)
|
72
146
|
if !connection.supports_insert_conflict_target?
|
73
147
|
return if unique_by.nil?
|
@@ -77,8 +151,9 @@ module ActiveRecord
|
|
77
151
|
|
78
152
|
name_or_columns = unique_by || model.primary_key
|
79
153
|
match = Array(name_or_columns).map(&:to_s)
|
154
|
+
sorted_match = match.sort
|
80
155
|
|
81
|
-
if index = unique_indexes.find { |i| match.include?(i.name) || i.columns ==
|
156
|
+
if index = unique_indexes.find { |i| match.include?(i.name) || Array(i.columns).sort == sorted_match }
|
82
157
|
index
|
83
158
|
elsif match == primary_keys
|
84
159
|
unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
|
@@ -126,15 +201,28 @@ module ActiveRecord
|
|
126
201
|
|
127
202
|
|
128
203
|
def verify_attributes(attributes)
|
129
|
-
if
|
204
|
+
if keys_including_timestamps != attributes.keys.to_set
|
130
205
|
raise ArgumentError, "All objects being inserted must have the same keys"
|
131
206
|
end
|
132
207
|
end
|
133
208
|
|
209
|
+
def disallow_raw_sql!(value)
|
210
|
+
return if !value.is_a?(String) || Arel.arel_node?(value)
|
211
|
+
|
212
|
+
raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
|
213
|
+
"SQL) called: #{value}. " \
|
214
|
+
"Known-safe values can be passed " \
|
215
|
+
"by wrapping them in Arel.sql()."
|
216
|
+
end
|
217
|
+
|
218
|
+
def timestamps_for_create
|
219
|
+
model.all_timestamp_attributes_in_model.index_with(connection.high_precision_current_timestamp)
|
220
|
+
end
|
221
|
+
|
134
222
|
class Builder # :nodoc:
|
135
223
|
attr_reader :model
|
136
224
|
|
137
|
-
delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
|
225
|
+
delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
|
138
226
|
|
139
227
|
def initialize(insert_all)
|
140
228
|
@insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
|
@@ -145,9 +233,10 @@ module ActiveRecord
|
|
145
233
|
end
|
146
234
|
|
147
235
|
def values_list
|
148
|
-
types = extract_types_from_columns_on(model.table_name, keys:
|
236
|
+
types = extract_types_from_columns_on(model.table_name, keys: keys_including_timestamps)
|
149
237
|
|
150
238
|
values_list = insert_all.map_key_with_value do |key, value|
|
239
|
+
next value if Arel::Nodes::SqlLiteral === value
|
151
240
|
connection.with_yaml_fallback(types[key].serialize(value))
|
152
241
|
end
|
153
242
|
|
@@ -155,7 +244,19 @@ module ActiveRecord
|
|
155
244
|
end
|
156
245
|
|
157
246
|
def returning
|
158
|
-
|
247
|
+
return unless insert_all.returning
|
248
|
+
|
249
|
+
if insert_all.returning.is_a?(String)
|
250
|
+
insert_all.returning
|
251
|
+
else
|
252
|
+
Array(insert_all.returning).map do |attribute|
|
253
|
+
if model.attribute_alias?(attribute)
|
254
|
+
"#{quote_column(model.attribute_alias(attribute))} AS #{quote_column(attribute)}"
|
255
|
+
else
|
256
|
+
quote_column(attribute)
|
257
|
+
end
|
258
|
+
end.join(",")
|
259
|
+
end
|
159
260
|
end
|
160
261
|
|
161
262
|
def conflict_target
|
@@ -173,22 +274,30 @@ module ActiveRecord
|
|
173
274
|
end
|
174
275
|
|
175
276
|
def touch_model_timestamps_unless(&block)
|
176
|
-
|
277
|
+
return "" unless update_duplicates? && record_timestamps?
|
278
|
+
|
279
|
+
model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
|
177
280
|
if touch_timestamp_attribute?(column_name)
|
178
|
-
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE
|
281
|
+
"#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
|
179
282
|
end
|
180
|
-
end.
|
283
|
+
end.join
|
181
284
|
end
|
182
285
|
|
286
|
+
def raw_update_sql
|
287
|
+
insert_all.update_sql
|
288
|
+
end
|
289
|
+
|
290
|
+
alias raw_update_sql? raw_update_sql
|
291
|
+
|
183
292
|
private
|
184
293
|
attr_reader :connection, :insert_all
|
185
294
|
|
186
295
|
def touch_timestamp_attribute?(column_name)
|
187
|
-
|
296
|
+
insert_all.updatable_columns.exclude?(column_name)
|
188
297
|
end
|
189
298
|
|
190
299
|
def columns_list
|
191
|
-
format_columns(insert_all.
|
300
|
+
format_columns(insert_all.keys_including_timestamps)
|
192
301
|
end
|
193
302
|
|
194
303
|
def extract_types_from_columns_on(table_name, keys:)
|
@@ -205,7 +314,11 @@ module ActiveRecord
|
|
205
314
|
end
|
206
315
|
|
207
316
|
def quote_columns(columns)
|
208
|
-
columns.map(
|
317
|
+
columns.map { |column| quote_column(column) }
|
318
|
+
end
|
319
|
+
|
320
|
+
def quote_column(column)
|
321
|
+
connection.quote_column_name(column)
|
209
322
|
end
|
210
323
|
end
|
211
324
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
##
|
11
11
|
# :singleton-method:
|
12
12
|
# Indicates the format used to generate the timestamp in the cache key, if
|
13
|
-
# versioning is off. Accepts any of the symbols in
|
13
|
+
# versioning is off. Accepts any of the symbols in +Time::DATE_FORMATS+.
|
14
14
|
#
|
15
15
|
# This is +:usec+, by default.
|
16
16
|
class_attribute :cache_timestamp_format, instance_writer: false, default: :usec
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
21
21
|
# by a changing version in the #cache_version method.
|
22
22
|
#
|
23
|
-
# This is +true+, by default on Rails 5.2 and above.
|
23
|
+
# This is +true+, by default on \Rails 5.2 and above.
|
24
24
|
class_attribute :cache_versioning, instance_writer: false, default: false
|
25
25
|
|
26
26
|
##
|
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
28
28
|
# Indicates whether to use a stable #cache_key method that is accompanied
|
29
29
|
# by a changing version in the #cache_version method on collections.
|
30
30
|
#
|
31
|
-
# This is +false+, by default until Rails 6.1.
|
31
|
+
# This is +false+, by default until \Rails 6.1.
|
32
32
|
class_attribute :collection_cache_versioning, instance_writer: false, default: false
|
33
33
|
end
|
34
34
|
|
@@ -55,8 +55,8 @@ module ActiveRecord
|
|
55
55
|
# user = User.find_by(name: 'Phusion')
|
56
56
|
# user_path(user) # => "/users/Phusion"
|
57
57
|
def to_param
|
58
|
-
|
59
|
-
id
|
58
|
+
return unless id
|
59
|
+
Array(id).join(self.class.param_delimiter)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Returns a stable cache key that can be used to identify this record.
|
@@ -64,7 +64,7 @@ module ActiveRecord
|
|
64
64
|
# Product.new.cache_key # => "products/new"
|
65
65
|
# Product.find(5).cache_key # => "products/5"
|
66
66
|
#
|
67
|
-
# If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
|
67
|
+
# If ActiveRecord::Base.cache_versioning is turned off, as it was in \Rails 5.1 and earlier,
|
68
68
|
# the cache key will also include a version.
|
69
69
|
#
|
70
70
|
# Product.cache_versioning = false
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
79
79
|
timestamp = max_updated_column_timestamp
|
80
80
|
|
81
81
|
if timestamp
|
82
|
-
timestamp = timestamp.utc.
|
82
|
+
timestamp = timestamp.utc.to_fs(cache_timestamp_format)
|
83
83
|
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
84
84
|
else
|
85
85
|
"#{model_name.cache_key}/#{id}"
|
@@ -101,11 +101,12 @@ module ActiveRecord
|
|
101
101
|
timestamp = updated_at_before_type_cast
|
102
102
|
if can_use_fast_cache_version?(timestamp)
|
103
103
|
raw_timestamp_to_cache_version(timestamp)
|
104
|
+
|
104
105
|
elsif timestamp = updated_at
|
105
|
-
timestamp.utc.
|
106
|
+
timestamp.utc.to_fs(cache_timestamp_format)
|
106
107
|
end
|
107
108
|
elsif self.class.has_attribute?("updated_at")
|
108
|
-
raise ActiveModel::MissingAttributeError, "missing attribute
|
109
|
+
raise ActiveModel::MissingAttributeError, "missing attribute 'updated_at' for #{self.class}"
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
@@ -177,7 +178,7 @@ module ActiveRecord
|
|
177
178
|
def can_use_fast_cache_version?(timestamp)
|
178
179
|
timestamp.is_a?(String) &&
|
179
180
|
cache_timestamp_format == :usec &&
|
180
|
-
default_timezone == :utc &&
|
181
|
+
self.class.connection.default_timezone == :utc &&
|
181
182
|
!updated_at_came_from_user?
|
182
183
|
end
|
183
184
|
|