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
@@ -6,6 +6,13 @@ module ActiveRecord
|
|
6
6
|
module ModelSchema
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
+
##
|
10
|
+
# :method: id_value
|
11
|
+
# :call-seq: id_value
|
12
|
+
#
|
13
|
+
# Returns the underlying column value for a column named "id". Useful when defining
|
14
|
+
# a composite primary key including an "id" column so that the value is readable.
|
15
|
+
|
9
16
|
##
|
10
17
|
# :singleton-method: primary_key_prefix_type
|
11
18
|
# :call-seq: primary_key_prefix_type
|
@@ -126,9 +133,34 @@ module ActiveRecord
|
|
126
133
|
# +:immutable_string+. This setting does not affect the behavior of
|
127
134
|
# <tt>attribute :foo, :string</tt>. Defaults to false.
|
128
135
|
|
129
|
-
|
130
|
-
|
136
|
+
##
|
137
|
+
# :singleton-method: inheritance_column
|
138
|
+
# :call-seq: inheritance_column
|
139
|
+
#
|
140
|
+
# The name of the table column which stores the class name on single-table
|
141
|
+
# inheritance situations.
|
142
|
+
#
|
143
|
+
# The default inheritance column name is +type+, which means it's a
|
144
|
+
# reserved word inside Active Record. To be able to use single-table
|
145
|
+
# inheritance with another column name, or to use the column +type+ in
|
146
|
+
# your own model for something else, you can set +inheritance_column+:
|
147
|
+
#
|
148
|
+
# self.inheritance_column = 'zoink'
|
149
|
+
#
|
150
|
+
# If you wish to disable single-table inheritance altogether you can set
|
151
|
+
# +inheritance_column+ to +nil+
|
152
|
+
#
|
153
|
+
# self.inheritance_column = nil
|
154
|
+
|
155
|
+
##
|
156
|
+
# :singleton-method: inheritance_column=
|
157
|
+
# :call-seq: inheritance_column=(column)
|
158
|
+
#
|
159
|
+
# Defines the name of the table column which will store the class name on single-table
|
160
|
+
# inheritance situations.
|
131
161
|
|
162
|
+
included do
|
163
|
+
class_attribute :primary_key_prefix_type, instance_writer: false
|
132
164
|
class_attribute :table_name_prefix, instance_writer: false, default: ""
|
133
165
|
class_attribute :table_name_suffix, instance_writer: false, default: ""
|
134
166
|
class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
|
@@ -137,8 +169,15 @@ module ActiveRecord
|
|
137
169
|
class_attribute :implicit_order_column, instance_accessor: false
|
138
170
|
class_attribute :immutable_strings_by_default, instance_accessor: false
|
139
171
|
|
172
|
+
class_attribute :inheritance_column, instance_accessor: false, default: "type"
|
173
|
+
singleton_class.class_eval do
|
174
|
+
alias_method :_inheritance_column=, :inheritance_column=
|
175
|
+
private :_inheritance_column=
|
176
|
+
alias_method :inheritance_column=, :real_inheritance_column=
|
177
|
+
end
|
178
|
+
|
140
179
|
self.protected_environments = ["production"]
|
141
|
-
|
180
|
+
|
142
181
|
self.ignored_columns = [].freeze
|
143
182
|
|
144
183
|
delegate :type_for_attribute, :column_for_attribute, to: :class
|
@@ -153,8 +192,9 @@ module ActiveRecord
|
|
153
192
|
# artists, records => artists_records
|
154
193
|
# records, artists => artists_records
|
155
194
|
# music_artists, music_records => music_artists_records
|
195
|
+
# music.artists, music.records => music.artists_records
|
156
196
|
def self.derive_join_table_name(first_table, second_table) # :nodoc:
|
157
|
-
[first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
197
|
+
[first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*[_.])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
158
198
|
end
|
159
199
|
|
160
200
|
module ClassMethods
|
@@ -197,6 +237,21 @@ module ActiveRecord
|
|
197
237
|
# the table name guess for an Invoice class becomes "myapp_invoices".
|
198
238
|
# Invoice::Lineitem becomes "myapp_invoice_lineitems".
|
199
239
|
#
|
240
|
+
# Active Model Naming's +model_name+ is the base name used to guess the
|
241
|
+
# table name. In case a custom Active Model Name is defined, it will be
|
242
|
+
# used for the table name as well:
|
243
|
+
#
|
244
|
+
# class PostRecord < ActiveRecord::Base
|
245
|
+
# class << self
|
246
|
+
# def model_name
|
247
|
+
# ActiveModel::Name.new(self, nil, "Post")
|
248
|
+
# end
|
249
|
+
# end
|
250
|
+
# end
|
251
|
+
#
|
252
|
+
# PostRecord.table_name
|
253
|
+
# # => "posts"
|
254
|
+
#
|
200
255
|
# You can also set your own table name explicitly:
|
201
256
|
#
|
202
257
|
# class Mouse < ActiveRecord::Base
|
@@ -223,19 +278,21 @@ module ActiveRecord
|
|
223
278
|
@table_name = value
|
224
279
|
@quoted_table_name = nil
|
225
280
|
@arel_table = nil
|
226
|
-
@sequence_name = nil unless
|
281
|
+
@sequence_name = nil unless @explicit_sequence_name
|
227
282
|
@predicate_builder = nil
|
228
283
|
end
|
229
284
|
|
230
285
|
# Returns a quoted version of the table name, used to construct SQL statements.
|
231
286
|
def quoted_table_name
|
232
|
-
@quoted_table_name ||=
|
287
|
+
@quoted_table_name ||= adapter_class.quote_table_name(table_name)
|
233
288
|
end
|
234
289
|
|
235
290
|
# Computes the table name, (re)sets it internally, and returns it.
|
236
|
-
def reset_table_name
|
237
|
-
self.table_name = if
|
238
|
-
|
291
|
+
def reset_table_name # :nodoc:
|
292
|
+
self.table_name = if self == Base
|
293
|
+
nil
|
294
|
+
elsif abstract_class?
|
295
|
+
superclass.table_name
|
239
296
|
elsif superclass.abstract_class?
|
240
297
|
superclass.table_name || compute_table_name
|
241
298
|
else
|
@@ -243,11 +300,11 @@ module ActiveRecord
|
|
243
300
|
end
|
244
301
|
end
|
245
302
|
|
246
|
-
def full_table_name_prefix
|
303
|
+
def full_table_name_prefix # :nodoc:
|
247
304
|
(module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
|
248
305
|
end
|
249
306
|
|
250
|
-
def full_table_name_suffix
|
307
|
+
def full_table_name_suffix # :nodoc:
|
251
308
|
(module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
|
252
309
|
end
|
253
310
|
|
@@ -266,33 +323,14 @@ module ActiveRecord
|
|
266
323
|
@protected_environments = environments.map(&:to_s)
|
267
324
|
end
|
268
325
|
|
269
|
-
|
270
|
-
|
271
|
-
#
|
272
|
-
# The default inheritance column name is +type+, which means it's a
|
273
|
-
# reserved word inside Active Record. To be able to use single-table
|
274
|
-
# inheritance with another column name, or to use the column +type+ in
|
275
|
-
# your own model for something else, you can set +inheritance_column+:
|
276
|
-
#
|
277
|
-
# self.inheritance_column = 'zoink'
|
278
|
-
def inheritance_column
|
279
|
-
(@inheritance_column ||= nil) || superclass.inheritance_column
|
280
|
-
end
|
281
|
-
|
282
|
-
# Sets the value of inheritance_column
|
283
|
-
def inheritance_column=(value)
|
284
|
-
@inheritance_column = value.to_s
|
285
|
-
@explicit_inheritance_column = true
|
326
|
+
def real_inheritance_column=(value) # :nodoc:
|
327
|
+
self._inheritance_column = value.to_s
|
286
328
|
end
|
287
329
|
|
288
330
|
# The list of columns names the model should ignore. Ignored columns won't have attribute
|
289
331
|
# accessors defined, and won't be referenced in SQL queries.
|
290
332
|
def ignored_columns
|
291
|
-
|
292
|
-
@ignored_columns
|
293
|
-
else
|
294
|
-
superclass.ignored_columns
|
295
|
-
end
|
333
|
+
@ignored_columns || superclass.ignored_columns
|
296
334
|
end
|
297
335
|
|
298
336
|
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
@@ -313,7 +351,7 @@ module ActiveRecord
|
|
313
351
|
# # name :string, limit: 255
|
314
352
|
# # category :string, limit: 255
|
315
353
|
#
|
316
|
-
# self.ignored_columns
|
354
|
+
# self.ignored_columns += [:category]
|
317
355
|
# end
|
318
356
|
#
|
319
357
|
# The schema still contains "category", but now the model omits it, so any meta-driven code or
|
@@ -339,9 +377,9 @@ module ActiveRecord
|
|
339
377
|
end
|
340
378
|
end
|
341
379
|
|
342
|
-
def reset_sequence_name
|
380
|
+
def reset_sequence_name # :nodoc:
|
343
381
|
@explicit_sequence_name = false
|
344
|
-
@sequence_name =
|
382
|
+
@sequence_name = with_connection { |c| c.default_sequence_name(table_name, primary_key) }
|
345
383
|
end
|
346
384
|
|
347
385
|
# Sets the name of the sequence to use when generating ids to the given
|
@@ -366,71 +404,53 @@ module ActiveRecord
|
|
366
404
|
# Determines if the primary key values should be selected from their
|
367
405
|
# corresponding sequence before the insert statement.
|
368
406
|
def prefetch_primary_key?
|
369
|
-
|
407
|
+
with_connection { |c| c.prefetch_primary_key?(table_name) }
|
370
408
|
end
|
371
409
|
|
372
410
|
# Returns the next value that will be used as the primary key on
|
373
411
|
# an insert statement.
|
374
412
|
def next_sequence_value
|
375
|
-
|
413
|
+
with_connection { |c| c.next_sequence_value(sequence_name) }
|
376
414
|
end
|
377
415
|
|
378
416
|
# Indicates whether the table associated with this class exists
|
379
417
|
def table_exists?
|
380
|
-
|
418
|
+
schema_cache.data_source_exists?(table_name)
|
381
419
|
end
|
382
420
|
|
383
421
|
def attributes_builder # :nodoc:
|
384
|
-
|
422
|
+
@attributes_builder ||= begin
|
385
423
|
defaults = _default_attributes.except(*(column_names - [primary_key]))
|
386
|
-
|
424
|
+
ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
|
387
425
|
end
|
388
|
-
@attributes_builder
|
389
426
|
end
|
390
427
|
|
391
428
|
def columns_hash # :nodoc:
|
392
|
-
load_schema
|
429
|
+
load_schema unless @columns_hash
|
393
430
|
@columns_hash
|
394
431
|
end
|
395
432
|
|
396
433
|
def columns
|
397
|
-
load_schema
|
434
|
+
load_schema unless @columns
|
398
435
|
@columns ||= columns_hash.values.freeze
|
399
436
|
end
|
400
437
|
|
401
|
-
def
|
402
|
-
|
403
|
-
|
438
|
+
def _returning_columns_for_insert(connection) # :nodoc:
|
439
|
+
@_returning_columns_for_insert ||= begin
|
440
|
+
auto_populated_columns = columns.filter_map do |c|
|
441
|
+
c.name if connection.return_value_after_insert?(c)
|
442
|
+
end
|
443
|
+
|
444
|
+
auto_populated_columns.empty? ? Array(primary_key) : auto_populated_columns
|
445
|
+
end
|
404
446
|
end
|
405
447
|
|
406
448
|
def yaml_encoder # :nodoc:
|
407
449
|
@yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
|
408
450
|
end
|
409
451
|
|
410
|
-
# Returns the type of the attribute with the given name, after applying
|
411
|
-
# all modifiers. This method is the only valid source of information for
|
412
|
-
# anything related to the types of a model's attributes. This method will
|
413
|
-
# access the database and load the model's schema if it is required.
|
414
|
-
#
|
415
|
-
# The return value of this method will implement the interface described
|
416
|
-
# by ActiveModel::Type::Value (though the object itself may not subclass
|
417
|
-
# it).
|
418
|
-
#
|
419
|
-
# +attr_name+ The name of the attribute to retrieve the type for. Must be
|
420
|
-
# a string or a symbol.
|
421
|
-
def type_for_attribute(attr_name, &block)
|
422
|
-
attr_name = attr_name.to_s
|
423
|
-
attr_name = attribute_aliases[attr_name] || attr_name
|
424
|
-
|
425
|
-
if block
|
426
|
-
attribute_types.fetch(attr_name, &block)
|
427
|
-
else
|
428
|
-
attribute_types[attr_name]
|
429
|
-
end
|
430
|
-
end
|
431
|
-
|
432
452
|
# Returns the column object for the named attribute.
|
433
|
-
# Returns an
|
453
|
+
# Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
|
434
454
|
# named attribute does not exist.
|
435
455
|
#
|
436
456
|
# class Person < ActiveRecord::Base
|
@@ -456,11 +476,6 @@ module ActiveRecord
|
|
456
476
|
@column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
|
457
477
|
end
|
458
478
|
|
459
|
-
def _default_attributes # :nodoc:
|
460
|
-
load_schema
|
461
|
-
@default_attributes ||= ActiveModel::AttributeSet.new({})
|
462
|
-
end
|
463
|
-
|
464
479
|
# Returns an array of column names as strings.
|
465
480
|
def column_names
|
466
481
|
@column_names ||= columns.map(&:name).freeze
|
@@ -486,9 +501,9 @@ module ActiveRecord
|
|
486
501
|
#
|
487
502
|
# The most common usage pattern for this method is probably in a migration,
|
488
503
|
# when just after creating a table you want to populate it with some default
|
489
|
-
# values,
|
504
|
+
# values, e.g.:
|
490
505
|
#
|
491
|
-
# class CreateJobLevels < ActiveRecord::Migration[
|
506
|
+
# class CreateJobLevels < ActiveRecord::Migration[7.2]
|
492
507
|
# def up
|
493
508
|
# create_table :job_levels do |t|
|
494
509
|
# t.integer :id
|
@@ -508,41 +523,65 @@ module ActiveRecord
|
|
508
523
|
# end
|
509
524
|
# end
|
510
525
|
def reset_column_information
|
511
|
-
|
526
|
+
connection_pool.active_connection&.clear_cache!
|
512
527
|
([self] + descendants).each(&:undefine_attribute_methods)
|
513
|
-
|
528
|
+
schema_cache.clear_data_source_cache!(table_name)
|
514
529
|
|
515
530
|
reload_schema_from_cache
|
516
531
|
initialize_find_by_cache
|
517
532
|
end
|
518
533
|
|
534
|
+
def load_schema # :nodoc:
|
535
|
+
return if schema_loaded?
|
536
|
+
@load_schema_monitor.synchronize do
|
537
|
+
return if schema_loaded?
|
538
|
+
|
539
|
+
load_schema!
|
540
|
+
|
541
|
+
@schema_loaded = true
|
542
|
+
rescue
|
543
|
+
reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
|
544
|
+
raise
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
519
548
|
protected
|
520
549
|
def initialize_load_schema_monitor
|
521
550
|
@load_schema_monitor = Monitor.new
|
522
551
|
end
|
523
552
|
|
553
|
+
def reload_schema_from_cache(recursive = true)
|
554
|
+
@_returning_columns_for_insert = nil
|
555
|
+
@arel_table = nil
|
556
|
+
@column_names = nil
|
557
|
+
@symbol_column_to_string_name_hash = nil
|
558
|
+
@content_columns = nil
|
559
|
+
@column_defaults = nil
|
560
|
+
@attributes_builder = nil
|
561
|
+
@columns = nil
|
562
|
+
@columns_hash = nil
|
563
|
+
@schema_loaded = false
|
564
|
+
@attribute_names = nil
|
565
|
+
@yaml_encoder = nil
|
566
|
+
if recursive
|
567
|
+
subclasses.each do |descendant|
|
568
|
+
descendant.send(:reload_schema_from_cache)
|
569
|
+
end
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
524
573
|
private
|
525
574
|
def inherited(child_class)
|
526
575
|
super
|
527
576
|
child_class.initialize_load_schema_monitor
|
577
|
+
child_class.reload_schema_from_cache(false)
|
578
|
+
child_class.class_eval do
|
579
|
+
@ignored_columns = nil
|
580
|
+
end
|
528
581
|
end
|
529
582
|
|
530
583
|
def schema_loaded?
|
531
|
-
|
532
|
-
end
|
533
|
-
|
534
|
-
def load_schema
|
535
|
-
return if schema_loaded?
|
536
|
-
@load_schema_monitor.synchronize do
|
537
|
-
return if defined?(@columns_hash) && @columns_hash
|
538
|
-
|
539
|
-
load_schema!
|
540
|
-
|
541
|
-
@schema_loaded = true
|
542
|
-
rescue
|
543
|
-
reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
|
544
|
-
raise
|
545
|
-
end
|
584
|
+
@schema_loaded
|
546
585
|
end
|
547
586
|
|
548
587
|
def load_schema!
|
@@ -550,45 +589,14 @@ module ActiveRecord
|
|
550
589
|
raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
|
551
590
|
end
|
552
591
|
|
553
|
-
columns_hash =
|
592
|
+
columns_hash = schema_cache.columns_hash(table_name)
|
554
593
|
columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
|
555
594
|
@columns_hash = columns_hash.freeze
|
556
|
-
@columns_hash.each do |name, column|
|
557
|
-
type = connection.lookup_cast_type_from_column(column)
|
558
|
-
type = _convert_type_from_options(type)
|
559
|
-
warn_if_deprecated_type(column)
|
560
|
-
define_attribute(
|
561
|
-
name,
|
562
|
-
type,
|
563
|
-
default: column.default,
|
564
|
-
user_provided_default: false
|
565
|
-
)
|
566
|
-
end
|
567
|
-
end
|
568
|
-
|
569
|
-
def reload_schema_from_cache
|
570
|
-
@arel_table = nil
|
571
|
-
@column_names = nil
|
572
|
-
@symbol_column_to_string_name_hash = nil
|
573
|
-
@attribute_types = nil
|
574
|
-
@content_columns = nil
|
575
|
-
@default_attributes = nil
|
576
|
-
@column_defaults = nil
|
577
|
-
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
578
|
-
@attributes_builder = nil
|
579
|
-
@columns = nil
|
580
|
-
@columns_hash = nil
|
581
|
-
@schema_loaded = false
|
582
|
-
@attribute_names = nil
|
583
|
-
@yaml_encoder = nil
|
584
|
-
direct_descendants.each do |descendant|
|
585
|
-
descendant.send(:reload_schema_from_cache)
|
586
|
-
end
|
587
595
|
end
|
588
596
|
|
589
597
|
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
590
|
-
def undecorated_table_name(
|
591
|
-
table_name =
|
598
|
+
def undecorated_table_name(model_name)
|
599
|
+
table_name = model_name.to_s.demodulize.underscore
|
592
600
|
pluralize_table_names ? table_name.pluralize : table_name
|
593
601
|
end
|
594
602
|
|
@@ -602,45 +610,21 @@ module ActiveRecord
|
|
602
610
|
contained += "_"
|
603
611
|
end
|
604
612
|
|
605
|
-
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(
|
613
|
+
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
|
606
614
|
else
|
607
|
-
# STI subclasses always use their superclass' table.
|
615
|
+
# STI subclasses always use their superclass's table.
|
608
616
|
base_class.table_name
|
609
617
|
end
|
610
618
|
end
|
611
619
|
|
612
|
-
def
|
613
|
-
|
614
|
-
type.to_immutable_string
|
615
|
-
else
|
616
|
-
type
|
617
|
-
end
|
618
|
-
end
|
619
|
-
|
620
|
-
def warn_if_deprecated_type(column)
|
621
|
-
return if attributes_to_define_after_schema_loads.key?(column.name)
|
622
|
-
return unless column.respond_to?(:oid)
|
620
|
+
def type_for_column(connection, column)
|
621
|
+
type = connection.lookup_cast_type_from_column(column)
|
623
622
|
|
624
|
-
if
|
625
|
-
|
626
|
-
else
|
627
|
-
array_arguments = ""
|
623
|
+
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
624
|
+
type = type.to_immutable_string
|
628
625
|
end
|
629
626
|
|
630
|
-
|
631
|
-
precision_arguments = column.precision.presence && ", precision: #{column.precision}"
|
632
|
-
ActiveSupport::Deprecation.warn(<<~WARNING)
|
633
|
-
The behavior of the `:interval` type will be changing in Rails 7.0
|
634
|
-
to return an `ActiveSupport::Duration` object. If you'd like to keep
|
635
|
-
the old behavior, you can add this line to #{self.name} model:
|
636
|
-
|
637
|
-
attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
|
638
|
-
|
639
|
-
If you'd like the new behavior today, you can add this line:
|
640
|
-
|
641
|
-
attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
|
642
|
-
WARNING
|
643
|
-
end
|
627
|
+
type
|
644
628
|
end
|
645
629
|
end
|
646
630
|
end
|
@@ -5,7 +5,7 @@ require "active_support/core_ext/module/redefine_method"
|
|
5
5
|
require "active_support/core_ext/hash/indifferent_access"
|
6
6
|
|
7
7
|
module ActiveRecord
|
8
|
-
module NestedAttributes
|
8
|
+
module NestedAttributes # :nodoc:
|
9
9
|
class TooManyRecords < ActiveRecordError
|
10
10
|
end
|
11
11
|
|
@@ -15,7 +15,7 @@ module ActiveRecord
|
|
15
15
|
class_attribute :nested_attributes_options, instance_writer: false, default: {}
|
16
16
|
end
|
17
17
|
|
18
|
-
# = Active Record Nested Attributes
|
18
|
+
# = Active Record Nested \Attributes
|
19
19
|
#
|
20
20
|
# Nested attributes allow you to save attributes on associated records
|
21
21
|
# through the parent. By default nested attribute updating is turned off
|
@@ -180,7 +180,7 @@ module ActiveRecord
|
|
180
180
|
# member.posts.second.title # => '[UPDATED] other post'
|
181
181
|
#
|
182
182
|
# However, the above applies if the parent model is being updated as well.
|
183
|
-
# For example,
|
183
|
+
# For example, if you wanted to create a +member+ named _joe_ and wanted to
|
184
184
|
# update the +posts+ at the same time, that would give an
|
185
185
|
# ActiveRecord::RecordNotFound error.
|
186
186
|
#
|
@@ -245,18 +245,19 @@ module ActiveRecord
|
|
245
245
|
#
|
246
246
|
# === Validating the presence of a parent model
|
247
247
|
#
|
248
|
-
#
|
249
|
-
#
|
250
|
-
#
|
248
|
+
# The +belongs_to+ association validates the presence of the parent model
|
249
|
+
# by default. You can disable this behavior by specifying <code>optional: true</code>.
|
250
|
+
# This can be used, for example, when conditionally validating the presence
|
251
|
+
# of the parent model:
|
251
252
|
#
|
252
|
-
# class
|
253
|
-
# has_many :
|
254
|
-
# accepts_nested_attributes_for :
|
253
|
+
# class Veterinarian < ActiveRecord::Base
|
254
|
+
# has_many :patients, inverse_of: :veterinarian
|
255
|
+
# accepts_nested_attributes_for :patients
|
255
256
|
# end
|
256
257
|
#
|
257
|
-
# class
|
258
|
-
# belongs_to :
|
259
|
-
#
|
258
|
+
# class Patient < ActiveRecord::Base
|
259
|
+
# belongs_to :veterinarian, inverse_of: :patients, optional: true
|
260
|
+
# validates :veterinarian, presence: true, unless: -> { awaiting_intake }
|
260
261
|
# end
|
261
262
|
#
|
262
263
|
# Note that if you do not specify the +:inverse_of+ option, then
|
@@ -279,6 +280,24 @@ module ActiveRecord
|
|
279
280
|
# member = Member.new
|
280
281
|
# member.avatar_attributes = {icon: 'sad'}
|
281
282
|
# member.avatar.width # => 200
|
283
|
+
#
|
284
|
+
# === Creating forms with nested attributes
|
285
|
+
#
|
286
|
+
# Use ActionView::Helpers::FormHelper#fields_for to create form elements for
|
287
|
+
# nested attributes.
|
288
|
+
#
|
289
|
+
# Integration test params should reflect the structure of the form. For
|
290
|
+
# example:
|
291
|
+
#
|
292
|
+
# post members_path, params: {
|
293
|
+
# member: {
|
294
|
+
# name: 'joe',
|
295
|
+
# posts_attributes: {
|
296
|
+
# '0' => { title: 'Foo' },
|
297
|
+
# '1' => { title: 'Bar' }
|
298
|
+
# }
|
299
|
+
# }
|
300
|
+
# }
|
282
301
|
module ClassMethods
|
283
302
|
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
|
284
303
|
|
@@ -288,7 +307,7 @@ module ActiveRecord
|
|
288
307
|
# [:allow_destroy]
|
289
308
|
# If true, destroys any members from the attributes hash with a
|
290
309
|
# <tt>_destroy</tt> key and a value that evaluates to +true+
|
291
|
-
# (e.g. 1, '1', true, or 'true'). This option is
|
310
|
+
# (e.g. 1, '1', true, or 'true'). This option is false by default.
|
292
311
|
# [:reject_if]
|
293
312
|
# Allows you to specify a Proc or a Symbol pointing to a method
|
294
313
|
# that checks whether a record should be built for a certain attribute
|
@@ -313,11 +332,11 @@ module ActiveRecord
|
|
313
332
|
# nested attributes are going to be used when an associated record already
|
314
333
|
# exists. In general, an existing record may either be updated with the
|
315
334
|
# new set of attribute values or be replaced by a wholly new record
|
316
|
-
# containing those values. By default the +:update_only+ option is
|
335
|
+
# containing those values. By default the +:update_only+ option is false
|
317
336
|
# and the nested attributes are used to update the existing record only
|
318
337
|
# if they include the record's <tt>:id</tt> value. Otherwise a new
|
319
338
|
# record will be instantiated and used to replace the existing one.
|
320
|
-
# However if the +:update_only+ option is
|
339
|
+
# However if the +:update_only+ option is true, the nested attributes
|
321
340
|
# are used to update the record's attributes always, regardless of
|
322
341
|
# whether the <tt>:id</tt> is present. The option is ignored for collection
|
323
342
|
# associations.
|
@@ -374,11 +393,11 @@ module ActiveRecord
|
|
374
393
|
end
|
375
394
|
end
|
376
395
|
|
377
|
-
# Returns ActiveRecord::AutosaveAssociation
|
396
|
+
# Returns ActiveRecord::AutosaveAssociation#marked_for_destruction? It's
|
378
397
|
# used in conjunction with fields_for to build a form element for the
|
379
398
|
# destruction of this association.
|
380
399
|
#
|
381
|
-
# See ActionView::Helpers::FormHelper
|
400
|
+
# See ActionView::Helpers::FormHelper#fields_for for more info.
|
382
401
|
def _destroy
|
383
402
|
marked_for_destruction?
|
384
403
|
end
|
@@ -402,10 +421,15 @@ module ActiveRecord
|
|
402
421
|
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
|
403
422
|
# then the existing record will be marked for destruction.
|
404
423
|
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
405
|
-
options = nested_attributes_options[association_name]
|
406
424
|
if attributes.respond_to?(:permitted?)
|
407
425
|
attributes = attributes.to_h
|
408
426
|
end
|
427
|
+
|
428
|
+
unless attributes.is_a?(Hash)
|
429
|
+
raise ArgumentError, "Hash expected for `#{association_name}` attributes, got #{attributes.class.name}"
|
430
|
+
end
|
431
|
+
|
432
|
+
options = nested_attributes_options[association_name]
|
409
433
|
attributes = attributes.with_indifferent_access
|
410
434
|
existing_record = send(association_name)
|
411
435
|
|
@@ -467,7 +491,7 @@ module ActiveRecord
|
|
467
491
|
end
|
468
492
|
|
469
493
|
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
470
|
-
raise ArgumentError, "Hash or Array expected for
|
494
|
+
raise ArgumentError, "Hash or Array expected for `#{association_name}` attributes, got #{attributes_collection.class.name}"
|
471
495
|
end
|
472
496
|
|
473
497
|
check_record_limit!(options[:limit], attributes_collection)
|
@@ -486,11 +510,11 @@ module ActiveRecord
|
|
486
510
|
existing_records = if association.loaded?
|
487
511
|
association.target
|
488
512
|
else
|
489
|
-
attribute_ids = attributes_collection.
|
513
|
+
attribute_ids = attributes_collection.filter_map { |a| a["id"] || a[:id] }
|
490
514
|
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
491
515
|
end
|
492
516
|
|
493
|
-
attributes_collection.
|
517
|
+
records = attributes_collection.map do |attributes|
|
494
518
|
if attributes.respond_to?(:permitted?)
|
495
519
|
attributes = attributes.to_h
|
496
520
|
end
|
@@ -513,11 +537,14 @@ module ActiveRecord
|
|
513
537
|
end
|
514
538
|
|
515
539
|
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
540
|
+
existing_record
|
516
541
|
end
|
517
542
|
else
|
518
543
|
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
519
544
|
end
|
520
545
|
end
|
546
|
+
|
547
|
+
association.nested_attributes_target = records
|
521
548
|
end
|
522
549
|
|
523
550
|
# Takes in a limit and checks if the attributes_collection has too many
|
@@ -26,20 +26,20 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class << self
|
29
|
-
def apply_to(klass)
|
29
|
+
def apply_to(klass) # :nodoc:
|
30
30
|
klasses.push(klass)
|
31
31
|
yield
|
32
32
|
ensure
|
33
33
|
klasses.pop
|
34
34
|
end
|
35
35
|
|
36
|
-
def applied_to?(klass)
|
36
|
+
def applied_to?(klass) # :nodoc:
|
37
37
|
klasses.any? { |k| k >= klass }
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
41
41
|
def klasses
|
42
|
-
|
42
|
+
ActiveSupport::IsolatedExecutionState[:active_record_no_touching_classes] ||= []
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|