activerecord 6.1.7 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +520 -1385
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- 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/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +404 -509
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +2 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +51 -49
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -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 +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- 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 +377 -142
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
- 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 +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- 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 +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- 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 +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/interval.rb +1 -1
- 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/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- 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 +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- 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 +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +276 -251
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- 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 +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -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 +170 -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_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +163 -63
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- 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 +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- 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 +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -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 +374 -177
- data/lib/active_record/model_schema.rb +143 -159
- data/lib/active_record/nested_attributes.rb +48 -21
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +234 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- 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 +325 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +300 -111
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +842 -150
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- 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 +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +277 -149
- 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 +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- 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 -7
- 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/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- 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 +64 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- 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/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -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/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- 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 +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- 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/templates/create_table_migration.rb.tt +4 -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 +100 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Scoping
|
@@ -24,11 +24,23 @@ module ActiveRecord
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def current_scope(skip_inherited_scope = false)
|
27
|
-
ScopeRegistry.
|
27
|
+
ScopeRegistry.current_scope(self, skip_inherited_scope)
|
28
28
|
end
|
29
29
|
|
30
30
|
def current_scope=(scope)
|
31
|
-
ScopeRegistry.
|
31
|
+
ScopeRegistry.set_current_scope(self, scope)
|
32
|
+
end
|
33
|
+
|
34
|
+
def global_current_scope(skip_inherited_scope = false)
|
35
|
+
ScopeRegistry.global_current_scope(self, skip_inherited_scope)
|
36
|
+
end
|
37
|
+
|
38
|
+
def global_current_scope=(scope)
|
39
|
+
ScopeRegistry.set_global_current_scope(self, scope)
|
40
|
+
end
|
41
|
+
|
42
|
+
def scope_registry
|
43
|
+
ScopeRegistry.instance
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
@@ -45,8 +57,8 @@ module ActiveRecord
|
|
45
57
|
end
|
46
58
|
|
47
59
|
# This class stores the +:current_scope+ and +:ignore_default_scope+ values
|
48
|
-
# for different classes. The registry is stored as a thread
|
49
|
-
#
|
60
|
+
# for different classes. The registry is stored as either a thread or fiber
|
61
|
+
# local depending on the application configuration.
|
50
62
|
#
|
51
63
|
# This class allows you to store and get the scope values on different
|
52
64
|
# classes and different types of scopes. For example, if you are attempting
|
@@ -54,51 +66,70 @@ module ActiveRecord
|
|
54
66
|
# following code:
|
55
67
|
#
|
56
68
|
# registry = ActiveRecord::Scoping::ScopeRegistry
|
57
|
-
# registry.
|
69
|
+
# registry.set_current_scope(Board, some_new_scope)
|
58
70
|
#
|
59
71
|
# Now when you run:
|
60
72
|
#
|
61
|
-
# registry.
|
62
|
-
#
|
63
|
-
# You will obtain whatever was defined in +some_new_scope+. The #value_for
|
64
|
-
# and #set_value_for methods are delegated to the current ScopeRegistry
|
65
|
-
# object, so the above example code can also be called as:
|
73
|
+
# registry.current_scope(Board)
|
66
74
|
#
|
67
|
-
#
|
68
|
-
# Board, some_new_scope)
|
75
|
+
# You will obtain whatever was defined in +some_new_scope+.
|
69
76
|
class ScopeRegistry # :nodoc:
|
70
|
-
|
77
|
+
class << self
|
78
|
+
delegate :current_scope, :set_current_scope, :ignore_default_scope, :set_ignore_default_scope,
|
79
|
+
:global_current_scope, :set_global_current_scope, to: :instance
|
71
80
|
|
72
|
-
|
81
|
+
def instance
|
82
|
+
ActiveSupport::IsolatedExecutionState[:active_record_scope_registry] ||= new
|
83
|
+
end
|
84
|
+
end
|
73
85
|
|
74
86
|
def initialize
|
75
|
-
@
|
87
|
+
@current_scope = {}
|
88
|
+
@ignore_default_scope = {}
|
89
|
+
@global_current_scope = {}
|
76
90
|
end
|
77
91
|
|
78
|
-
|
79
|
-
|
80
|
-
raise_invalid_scope_type!(scope_type)
|
81
|
-
return @registry[scope_type][model.name] if skip_inherited_scope
|
82
|
-
klass = model
|
83
|
-
base = model.base_class
|
84
|
-
while klass <= base
|
85
|
-
value = @registry[scope_type][klass.name]
|
86
|
-
return value if value
|
87
|
-
klass = klass.superclass
|
88
|
-
end
|
92
|
+
def current_scope(model, skip_inherited_scope = false)
|
93
|
+
value_for(@current_scope, model, skip_inherited_scope)
|
89
94
|
end
|
90
95
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
def set_current_scope(model, value)
|
97
|
+
set_value_for(@current_scope, model, value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def ignore_default_scope(model, skip_inherited_scope = false)
|
101
|
+
value_for(@ignore_default_scope, model, skip_inherited_scope)
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_ignore_default_scope(model, value)
|
105
|
+
set_value_for(@ignore_default_scope, model, value)
|
106
|
+
end
|
107
|
+
|
108
|
+
def global_current_scope(model, skip_inherited_scope = false)
|
109
|
+
value_for(@global_current_scope, model, skip_inherited_scope)
|
110
|
+
end
|
111
|
+
|
112
|
+
def set_global_current_scope(model, value)
|
113
|
+
set_value_for(@global_current_scope, model, value)
|
95
114
|
end
|
96
115
|
|
97
116
|
private
|
98
|
-
|
99
|
-
|
100
|
-
|
117
|
+
# Obtains the value for a given +scope_type+ and +model+.
|
118
|
+
def value_for(scope_type, model, skip_inherited_scope = false)
|
119
|
+
return scope_type[model.name] if skip_inherited_scope
|
120
|
+
klass = model
|
121
|
+
base = model.base_class
|
122
|
+
while klass != base
|
123
|
+
value = scope_type[klass.name]
|
124
|
+
return value if value
|
125
|
+
klass = klass.superclass
|
101
126
|
end
|
127
|
+
scope_type[klass.name]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets the +value+ for a given +scope_type+ and +model+.
|
131
|
+
def set_value_for(scope_type, model, value)
|
132
|
+
scope_type[model.name] = value
|
102
133
|
end
|
103
134
|
end
|
104
135
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module SecurePassword
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
include ActiveModel::SecurePassword
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
# Given a set of attributes, finds a record using the non-password
|
11
|
+
# attributes, and then authenticates that record using the password
|
12
|
+
# attributes. Returns the record if authentication succeeds; otherwise,
|
13
|
+
# returns +nil+.
|
14
|
+
#
|
15
|
+
# Regardless of whether a record is found, +authenticate_by+ will
|
16
|
+
# cryptographically digest the given password attributes. This behavior
|
17
|
+
# helps mitigate timing-based enumeration attacks, wherein an attacker can
|
18
|
+
# determine if a passworded record exists even without knowing the
|
19
|
+
# password.
|
20
|
+
#
|
21
|
+
# Raises an ArgumentError if the set of attributes doesn't contain at
|
22
|
+
# least one password and one non-password attribute.
|
23
|
+
#
|
24
|
+
# ==== Examples
|
25
|
+
#
|
26
|
+
# class User < ActiveRecord::Base
|
27
|
+
# has_secure_password
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# User.create(name: "John Doe", email: "jdoe@example.com", password: "abc123")
|
31
|
+
#
|
32
|
+
# User.authenticate_by(email: "jdoe@example.com", password: "abc123").name # => "John Doe" (in 373.4ms)
|
33
|
+
# User.authenticate_by(email: "jdoe@example.com", password: "wrong") # => nil (in 373.9ms)
|
34
|
+
# User.authenticate_by(email: "wrong@example.com", password: "abc123") # => nil (in 373.6ms)
|
35
|
+
#
|
36
|
+
# User.authenticate_by(email: "jdoe@example.com", password: nil) # => nil (no queries executed)
|
37
|
+
# User.authenticate_by(email: "jdoe@example.com", password: "") # => nil (no queries executed)
|
38
|
+
#
|
39
|
+
# User.authenticate_by(email: "jdoe@example.com") # => ArgumentError
|
40
|
+
# User.authenticate_by(password: "abc123") # => ArgumentError
|
41
|
+
def authenticate_by(attributes)
|
42
|
+
passwords, identifiers = attributes.to_h.partition do |name, value|
|
43
|
+
!has_attribute?(name) && has_attribute?("#{name}_digest")
|
44
|
+
end.map(&:to_h)
|
45
|
+
|
46
|
+
raise ArgumentError, "One or more password arguments are required" if passwords.empty?
|
47
|
+
raise ArgumentError, "One or more finder arguments are required" if identifiers.empty?
|
48
|
+
|
49
|
+
return if passwords.any? { |name, value| value.nil? || value.empty? }
|
50
|
+
|
51
|
+
if record = find_by(identifiers)
|
52
|
+
record if passwords.count { |name, value| record.public_send(:"authenticate_#{name}", value) } == passwords.size
|
53
|
+
else
|
54
|
+
new(passwords)
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -24,12 +24,26 @@ module ActiveRecord
|
|
24
24
|
# user.regenerate_token # => true
|
25
25
|
# user.regenerate_auth_token # => true
|
26
26
|
#
|
27
|
-
#
|
27
|
+
# +SecureRandom::base58+ is used to generate at minimum a 24-character unique token, so collisions are highly unlikely.
|
28
28
|
#
|
29
29
|
# Note that it's still possible to generate a race condition in the database in the same way that
|
30
30
|
# {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
|
31
31
|
# You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
|
32
|
-
|
32
|
+
#
|
33
|
+
# === Options
|
34
|
+
#
|
35
|
+
# [:length]
|
36
|
+
# Length of the Secure Random, with a minimum of 24 characters. It will
|
37
|
+
# default to 24.
|
38
|
+
#
|
39
|
+
# [:on]
|
40
|
+
# The callback when the value is generated. When called with <tt>on:
|
41
|
+
# :initialize</tt>, the value is generated in an
|
42
|
+
# <tt>after_initialize</tt> callback, otherwise the value will be used
|
43
|
+
# in a <tt>before_</tt> callback. When not specified, +:on+ will use the value of
|
44
|
+
# <tt>config.active_record.generate_secure_token_on</tt>, which defaults to +:initialize+
|
45
|
+
# starting in \Rails 7.1.
|
46
|
+
def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH, on: ActiveRecord.generate_secure_token_on)
|
33
47
|
if length < MINIMUM_TOKEN_LENGTH
|
34
48
|
raise MinimumLengthError, "Token requires a minimum length of #{MINIMUM_TOKEN_LENGTH} characters."
|
35
49
|
end
|
@@ -37,7 +51,11 @@ module ActiveRecord
|
|
37
51
|
# Load securerandom only when has_secure_token is used.
|
38
52
|
require "active_support/core_ext/securerandom"
|
39
53
|
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(length: length) }
|
40
|
-
|
54
|
+
set_callback on, on == :initialize ? :after : :before do
|
55
|
+
if new_record? && !query_attribute(attribute)
|
56
|
+
send("#{attribute}=", self.class.generate_unique_secure_token(length: length))
|
57
|
+
end
|
58
|
+
end
|
41
59
|
end
|
42
60
|
|
43
61
|
def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActiveRecord
|
3
|
+
module ActiveRecord # :nodoc:
|
4
4
|
# = Active Record \Serialization
|
5
5
|
module Serialization
|
6
6
|
extend ActiveSupport::Concern
|
@@ -20,5 +20,10 @@ module ActiveRecord #:nodoc:
|
|
20
20
|
|
21
21
|
super(options)
|
22
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def attribute_names_for_serialization
|
26
|
+
attribute_names
|
27
|
+
end
|
23
28
|
end
|
24
29
|
end
|
@@ -8,9 +8,19 @@ module ActiveRecord
|
|
8
8
|
included do
|
9
9
|
##
|
10
10
|
# :singleton-method:
|
11
|
-
# Set the secret used for the signed id verifier instance when using Active Record outside of Rails.
|
12
|
-
# Within Rails, this is automatically set using the Rails application key generator.
|
13
|
-
|
11
|
+
# Set the secret used for the signed id verifier instance when using Active Record outside of \Rails.
|
12
|
+
# Within \Rails, this is automatically set using the \Rails application key generator.
|
13
|
+
class_attribute :signed_id_verifier_secret, instance_writer: false
|
14
|
+
end
|
15
|
+
|
16
|
+
module RelationMethods # :nodoc:
|
17
|
+
def find_signed(...)
|
18
|
+
scoping { model.find_signed(...) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_signed!(...)
|
22
|
+
scoping { model.find_signed!(...) }
|
23
|
+
end
|
14
24
|
end
|
15
25
|
|
16
26
|
module ClassMethods
|
@@ -47,7 +57,7 @@ module ActiveRecord
|
|
47
57
|
end
|
48
58
|
end
|
49
59
|
|
50
|
-
# Works like
|
60
|
+
# Works like find_signed, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
|
51
61
|
# exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
|
52
62
|
# or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
|
53
63
|
# the valid signed id can't find a record.
|
@@ -66,7 +76,7 @@ module ActiveRecord
|
|
66
76
|
end
|
67
77
|
|
68
78
|
# The verifier instance that all signed ids are generated and verified from. By default, it'll be initialized
|
69
|
-
# with the class-level +signed_id_verifier_secret+, which within Rails comes from the
|
79
|
+
# with the class-level +signed_id_verifier_secret+, which within \Rails comes from the
|
70
80
|
# Rails.application.key_generator. By default, it's SHA256 for the digest and JSON for the serialization.
|
71
81
|
def signed_id_verifier
|
72
82
|
@signed_id_verifier ||= begin
|
@@ -76,7 +86,7 @@ module ActiveRecord
|
|
76
86
|
if secret.nil?
|
77
87
|
raise ArgumentError, "You must set ActiveRecord::Base.signed_id_verifier_secret to use signed ids"
|
78
88
|
else
|
79
|
-
ActiveSupport::MessageVerifier.new secret, digest: "SHA256", serializer: JSON
|
89
|
+
ActiveSupport::MessageVerifier.new secret, digest: "SHA256", serializer: JSON, url_safe: true
|
80
90
|
end
|
81
91
|
end
|
82
92
|
end
|
@@ -96,8 +106,17 @@ module ActiveRecord
|
|
96
106
|
|
97
107
|
|
98
108
|
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
109
|
+
#
|
99
110
|
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
100
|
-
#
|
111
|
+
# However, as with any message signed with a +ActiveSupport::MessageVerifier+,
|
112
|
+
# {the signed id is not encrypted}[link:classes/ActiveSupport/MessageVerifier.html#class-ActiveSupport::MessageVerifier-label-Signing+is+not+encryption].
|
113
|
+
# It's just encoded and protected against tampering.
|
114
|
+
#
|
115
|
+
# This means that the ID can be decoded by anyone; however, if tampered with (so to point to a different ID),
|
116
|
+
# the cryptographic signature will no longer match, and the signed id will be considered invalid and return nil
|
117
|
+
# when passed to +find_signed+ (or raise with +find_signed!+).
|
118
|
+
#
|
119
|
+
# It can furthermore be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
101
120
|
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
102
121
|
# record. If a purpose is set, this too must match.
|
103
122
|
#
|
@@ -109,8 +128,10 @@ module ActiveRecord
|
|
109
128
|
#
|
110
129
|
# And you then change your +find_signed+ calls to require this new purpose. Any old signed ids that were not
|
111
130
|
# created with the purpose will no longer find the record.
|
112
|
-
def signed_id(expires_in: nil, purpose: nil)
|
113
|
-
|
131
|
+
def signed_id(expires_in: nil, expires_at: nil, purpose: nil)
|
132
|
+
raise ArgumentError, "Cannot get a signed_id for a new record" if new_record?
|
133
|
+
|
134
|
+
self.class.signed_id_verifier.generate id, expires_in: expires_in, expires_at: expires_at, purpose: self.class.combine_signed_id_purposes(purpose)
|
114
135
|
end
|
115
136
|
end
|
116
137
|
end
|
@@ -4,14 +4,14 @@ module ActiveRecord
|
|
4
4
|
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
|
5
5
|
# Initializing the cache is done by passing the statement in the create block:
|
6
6
|
#
|
7
|
-
# cache = StatementCache.create(
|
7
|
+
# cache = StatementCache.create(ClothingItem.lease_connection) do |params|
|
8
8
|
# Book.where(name: "my book").where("author_id > 3")
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
# The cached statement is executed by using the
|
12
12
|
# {connection.execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute] method:
|
13
13
|
#
|
14
|
-
# cache.execute([],
|
14
|
+
# cache.execute([], ClothingItem.lease_connection)
|
15
15
|
#
|
16
16
|
# The relation returned by the block is cached, and for each
|
17
17
|
# {execute}[rdoc-ref:ConnectionAdapters::DatabaseStatements#execute]
|
@@ -20,13 +20,13 @@ module ActiveRecord
|
|
20
20
|
# If you want to cache the statement without the values you can use the +bind+ method of the
|
21
21
|
# block parameter.
|
22
22
|
#
|
23
|
-
# cache = StatementCache.create(
|
23
|
+
# cache = StatementCache.create(ClothingItem.lease_connection) do |params|
|
24
24
|
# Book.where(name: params.bind)
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
# And pass the bind values as the first argument of +execute+ call.
|
28
28
|
#
|
29
|
-
# cache.execute(["my book"],
|
29
|
+
# cache.execute(["my book"], ClothingItem.lease_connection)
|
30
30
|
class StatementCache # :nodoc:
|
31
31
|
class Substitute; end # :nodoc:
|
32
32
|
|
@@ -62,7 +62,7 @@ module ActiveRecord
|
|
62
62
|
end
|
63
63
|
|
64
64
|
class PartialQueryCollector
|
65
|
-
attr_accessor :preparable
|
65
|
+
attr_accessor :preparable, :retryable
|
66
66
|
|
67
67
|
def initialize
|
68
68
|
@parts = []
|
@@ -142,12 +142,12 @@ module ActiveRecord
|
|
142
142
|
@klass = klass
|
143
143
|
end
|
144
144
|
|
145
|
-
def execute(params, connection, &block)
|
145
|
+
def execute(params, connection, allow_retry: false, &block)
|
146
146
|
bind_values = bind_map.bind params
|
147
147
|
|
148
148
|
sql = query_builder.sql_for bind_values, connection
|
149
149
|
|
150
|
-
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
150
|
+
klass.find_by_sql(sql, bind_values, preparable: true, allow_retry: allow_retry, &block)
|
151
151
|
rescue ::RangeError
|
152
152
|
[]
|
153
153
|
end
|
data/lib/active_record/store.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
+
# = Active Record \Store
|
7
|
+
#
|
6
8
|
# Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
|
7
9
|
# It's like a simple key/value store baked into your record when you don't care about being able to
|
8
10
|
# query that store outside the context of a single record.
|
@@ -59,7 +61,7 @@ module ActiveRecord
|
|
59
61
|
# u.color = 'green'
|
60
62
|
# u.color_changed? # => true
|
61
63
|
# u.color_was # => 'black'
|
62
|
-
# u.color_change # => ['black', '
|
64
|
+
# u.color_change # => ['black', 'green']
|
63
65
|
#
|
64
66
|
# # Add additional accessors to an existing store through store_accessor
|
65
67
|
# class SuperUser < User
|
@@ -70,7 +72,7 @@ module ActiveRecord
|
|
70
72
|
#
|
71
73
|
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
72
74
|
#
|
73
|
-
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
|
75
|
+
# User.stored_attributes[:settings] # => [:color, :homepage, :two_factor_auth, :login_retry]
|
74
76
|
#
|
75
77
|
# == Overwriting default accessors
|
76
78
|
#
|
@@ -102,7 +104,8 @@ module ActiveRecord
|
|
102
104
|
|
103
105
|
module ClassMethods
|
104
106
|
def store(store_attribute, options = {})
|
105
|
-
|
107
|
+
coder = build_column_serializer(store_attribute, options[:coder], Object, options[:yaml])
|
108
|
+
serialize store_attribute, coder: IndifferentCoder.new(store_attribute, coder)
|
106
109
|
store_accessor(store_attribute, options[:accessors], **options.slice(:prefix, :suffix)) if options.has_key? :accessors
|
107
110
|
end
|
108
111
|
|
@@ -160,19 +163,19 @@ module ActiveRecord
|
|
160
163
|
|
161
164
|
define_method("saved_change_to_#{accessor_key}?") do
|
162
165
|
return false unless saved_change_to_attribute?(store_attribute)
|
163
|
-
prev_store, new_store =
|
166
|
+
prev_store, new_store = saved_changes[store_attribute]
|
164
167
|
prev_store&.dig(key) != new_store&.dig(key)
|
165
168
|
end
|
166
169
|
|
167
170
|
define_method("saved_change_to_#{accessor_key}") do
|
168
171
|
return unless saved_change_to_attribute?(store_attribute)
|
169
|
-
prev_store, new_store =
|
172
|
+
prev_store, new_store = saved_changes[store_attribute]
|
170
173
|
[prev_store&.dig(key), new_store&.dig(key)]
|
171
174
|
end
|
172
175
|
|
173
176
|
define_method("#{accessor_key}_before_last_save") do
|
174
177
|
return unless saved_change_to_attribute?(store_attribute)
|
175
|
-
prev_store, _new_store =
|
178
|
+
prev_store, _new_store = saved_changes[store_attribute]
|
176
179
|
prev_store&.dig(key)
|
177
180
|
end
|
178
181
|
end
|
@@ -225,10 +228,7 @@ module ActiveRecord
|
|
225
228
|
|
226
229
|
def self.write(object, attribute, key, value)
|
227
230
|
prepare(object, attribute)
|
228
|
-
if value != read(object, attribute, key)
|
229
|
-
object.public_send :"#{attribute}_will_change!"
|
230
|
-
object.public_send(attribute)[key] = value
|
231
|
-
end
|
231
|
+
object.public_send(attribute)[key] = value if value != read(object, attribute, key)
|
232
232
|
end
|
233
233
|
|
234
234
|
def self.prepare(object, attribute)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# = Active Record \Suppressor
|
5
|
+
#
|
4
6
|
# ActiveRecord::Suppressor prevents the receiver from being saved during
|
5
7
|
# a given block.
|
6
8
|
#
|
@@ -30,32 +32,28 @@ module ActiveRecord
|
|
30
32
|
module Suppressor
|
31
33
|
extend ActiveSupport::Concern
|
32
34
|
|
35
|
+
class << self
|
36
|
+
def registry # :nodoc:
|
37
|
+
ActiveSupport::IsolatedExecutionState[:active_record_suppressor_registry] ||= {}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
33
41
|
module ClassMethods
|
34
42
|
def suppress(&block)
|
35
|
-
previous_state =
|
36
|
-
|
43
|
+
previous_state = Suppressor.registry[name]
|
44
|
+
Suppressor.registry[name] = true
|
37
45
|
yield
|
38
46
|
ensure
|
39
|
-
|
47
|
+
Suppressor.registry[name] = previous_state
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
51
|
def save(**) # :nodoc:
|
44
|
-
|
52
|
+
Suppressor.registry[self.class.name] ? true : super
|
45
53
|
end
|
46
54
|
|
47
55
|
def save!(**) # :nodoc:
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class SuppressorRegistry # :nodoc:
|
53
|
-
extend ActiveSupport::PerThreadRegistry
|
54
|
-
|
55
|
-
attr_reader :suppressed
|
56
|
-
|
57
|
-
def initialize
|
58
|
-
@suppressed = {}
|
56
|
+
Suppressor.registry[self.class.name] ? true : super
|
59
57
|
end
|
60
58
|
end
|
61
59
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class TableMetadata # :nodoc:
|
5
|
-
delegate :join_primary_key, :join_foreign_key, :join_foreign_type, to: :reflection
|
5
|
+
delegate :join_primary_key, :join_primary_type, :join_foreign_key, :join_foreign_type, to: :reflection
|
6
6
|
|
7
7
|
def initialize(klass, arel_table, reflection = nil)
|
8
8
|
@klass = klass
|
@@ -19,11 +19,11 @@ module ActiveRecord
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def has_column?(column_name)
|
22
|
-
klass&.columns_hash
|
22
|
+
klass&.columns_hash&.key?(column_name)
|
23
23
|
end
|
24
24
|
|
25
25
|
def associated_with?(table_name)
|
26
|
-
klass&._reflect_on_association(table_name)
|
26
|
+
klass&._reflect_on_association(table_name)
|
27
27
|
end
|
28
28
|
|
29
29
|
def associated_table(table_name)
|
@@ -54,6 +54,10 @@ module ActiveRecord
|
|
54
54
|
reflection&.polymorphic?
|
55
55
|
end
|
56
56
|
|
57
|
+
def polymorphic_name_association
|
58
|
+
reflection&.polymorphic_name
|
59
|
+
end
|
60
|
+
|
57
61
|
def through_association?
|
58
62
|
reflection&.through_reflection?
|
59
63
|
end
|