activerecord 6.0.0 → 7.2.3
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 +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- 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 +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- 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 +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- 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 -25
- 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 +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- 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 +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- 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 +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- 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 +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +5 -6
- 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 +171 -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 +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- 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 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -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 +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- 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/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- 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 +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- 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 +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- 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 +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
|
@@ -1,187 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/core_ext/enumerable"
|
|
4
|
-
require "active_support/core_ext/string/conversions"
|
|
5
|
-
require "active_support/core_ext/module/remove_method"
|
|
6
|
-
require "active_record/errors"
|
|
7
|
-
|
|
8
3
|
module ActiveRecord
|
|
9
|
-
class AssociationNotFoundError < ConfigurationError #:nodoc:
|
|
10
|
-
def initialize(record = nil, association_name = nil)
|
|
11
|
-
if record && association_name
|
|
12
|
-
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
|
13
|
-
else
|
|
14
|
-
super("Association was not found.")
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
|
20
|
-
def initialize(reflection = nil, associated_class = nil)
|
|
21
|
-
if reflection
|
|
22
|
-
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
|
23
|
-
else
|
|
24
|
-
super("Could not find the inverse association.")
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
|
30
|
-
def initialize(owner_class_name = nil, reflection = nil)
|
|
31
|
-
if owner_class_name && reflection
|
|
32
|
-
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class_name}")
|
|
33
|
-
else
|
|
34
|
-
super("Could not find the association.")
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
|
40
|
-
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
|
41
|
-
if owner_class_name && reflection && source_reflection
|
|
42
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
|
|
43
|
-
else
|
|
44
|
-
super("Cannot have a has_many :through association.")
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
|
|
50
|
-
def initialize(owner_class_name = nil, reflection = nil)
|
|
51
|
-
if owner_class_name && reflection
|
|
52
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
|
53
|
-
else
|
|
54
|
-
super("Cannot have a has_many :through association.")
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
|
|
60
|
-
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
|
61
|
-
if owner_class_name && reflection && source_reflection
|
|
62
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
|
|
63
|
-
else
|
|
64
|
-
super("Cannot have a has_many :through association.")
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError #:nodoc:
|
|
70
|
-
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
|
71
|
-
if owner_class_name && reflection && through_reflection
|
|
72
|
-
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' where the :through association '#{owner_class_name}##{through_reflection.name}' is a collection. Specify a has_one or belongs_to association in the :through option instead.")
|
|
73
|
-
else
|
|
74
|
-
super("Cannot have a has_one :through association.")
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
class HasOneAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
|
|
80
|
-
def initialize(owner_class_name = nil, reflection = nil)
|
|
81
|
-
if owner_class_name && reflection
|
|
82
|
-
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
|
83
|
-
else
|
|
84
|
-
super("Cannot have a has_one :through association.")
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
|
|
90
|
-
def initialize(reflection = nil)
|
|
91
|
-
if reflection
|
|
92
|
-
through_reflection = reflection.through_reflection
|
|
93
|
-
source_reflection_names = reflection.source_reflection_names
|
|
94
|
-
source_associations = reflection.through_reflection.klass._reflections.keys
|
|
95
|
-
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ', locale: :en)} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ', locale: :en)}?")
|
|
96
|
-
else
|
|
97
|
-
super("Could not find the source association(s).")
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
class HasManyThroughOrderError < ActiveRecordError #:nodoc:
|
|
103
|
-
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
|
104
|
-
if owner_class_name && reflection && through_reflection
|
|
105
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through '#{owner_class_name}##{through_reflection.name}' before the through association is defined.")
|
|
106
|
-
else
|
|
107
|
-
super("Cannot have a has_many :through association before the through association is defined.")
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError #:nodoc:
|
|
113
|
-
def initialize(owner = nil, reflection = nil)
|
|
114
|
-
if owner && reflection
|
|
115
|
-
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
|
|
116
|
-
else
|
|
117
|
-
super("Cannot modify association.")
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
class AmbiguousSourceReflectionForThroughAssociation < ActiveRecordError # :nodoc:
|
|
123
|
-
def initialize(klass, macro, association_name, options, possible_sources)
|
|
124
|
-
example_options = options.dup
|
|
125
|
-
example_options[:source] = possible_sources.first
|
|
126
|
-
|
|
127
|
-
super("Ambiguous source reflection for through association. Please " \
|
|
128
|
-
"specify a :source directive on your declaration like:\n" \
|
|
129
|
-
"\n" \
|
|
130
|
-
" class #{klass} < ActiveRecord::Base\n" \
|
|
131
|
-
" #{macro} :#{association_name}, #{example_options}\n" \
|
|
132
|
-
" end"
|
|
133
|
-
)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection #:nodoc:
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection #:nodoc:
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
class ThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc:
|
|
144
|
-
def initialize(owner = nil, reflection = nil)
|
|
145
|
-
if owner && reflection
|
|
146
|
-
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
|
147
|
-
else
|
|
148
|
-
super("Through nested associations are read-only.")
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly #:nodoc:
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly #:nodoc:
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# This error is raised when trying to eager load a polymorphic association using a JOIN.
|
|
160
|
-
# Eager loading polymorphic associations is only possible with
|
|
161
|
-
# {ActiveRecord::Relation#preload}[rdoc-ref:QueryMethods#preload].
|
|
162
|
-
class EagerLoadPolymorphicError < ActiveRecordError
|
|
163
|
-
def initialize(reflection = nil)
|
|
164
|
-
if reflection
|
|
165
|
-
super("Cannot eagerly load the polymorphic association #{reflection.name.inspect}")
|
|
166
|
-
else
|
|
167
|
-
super("Eager load polymorphic error.")
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
|
|
173
|
-
# (has_many, has_one) when there is at least 1 child associated instance.
|
|
174
|
-
# ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
|
|
175
|
-
class DeleteRestrictionError < ActiveRecordError #:nodoc:
|
|
176
|
-
def initialize(name = nil)
|
|
177
|
-
if name
|
|
178
|
-
super("Cannot delete record because of dependent #{name}")
|
|
179
|
-
else
|
|
180
|
-
super("Delete restriction error.")
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
4
|
# See ActiveRecord::Associations::ClassMethods for documentation.
|
|
186
5
|
module Associations # :nodoc:
|
|
187
6
|
extend ActiveSupport::Autoload
|
|
@@ -196,7 +15,7 @@ module ActiveRecord
|
|
|
196
15
|
autoload :CollectionProxy
|
|
197
16
|
autoload :ThroughAssociation
|
|
198
17
|
|
|
199
|
-
module Builder
|
|
18
|
+
module Builder # :nodoc:
|
|
200
19
|
autoload :Association, "active_record/associations/builder/association"
|
|
201
20
|
autoload :SingularAssociation, "active_record/associations/builder/singular_association"
|
|
202
21
|
autoload :CollectionAssociation, "active_record/associations/builder/collection_association"
|
|
@@ -218,16 +37,18 @@ module ActiveRecord
|
|
|
218
37
|
autoload :Preloader
|
|
219
38
|
autoload :JoinDependency
|
|
220
39
|
autoload :AssociationScope
|
|
40
|
+
autoload :DisableJoinsAssociationScope
|
|
221
41
|
autoload :AliasTracker
|
|
222
42
|
end
|
|
223
43
|
|
|
224
44
|
def self.eager_load!
|
|
225
45
|
super
|
|
226
46
|
Preloader.eager_load!
|
|
47
|
+
JoinDependency.eager_load!
|
|
227
48
|
end
|
|
228
49
|
|
|
229
50
|
# Returns the association instance for the given name, instantiating it if it doesn't already exist
|
|
230
|
-
def association(name)
|
|
51
|
+
def association(name) # :nodoc:
|
|
231
52
|
association = association_instance_get(name)
|
|
232
53
|
|
|
233
54
|
if association.nil?
|
|
@@ -250,20 +71,10 @@ module ActiveRecord
|
|
|
250
71
|
super
|
|
251
72
|
end
|
|
252
73
|
|
|
253
|
-
def reload(*) # :nodoc:
|
|
254
|
-
clear_association_cache
|
|
255
|
-
super
|
|
256
|
-
end
|
|
257
|
-
|
|
258
74
|
private
|
|
259
|
-
# Clears out the association cache.
|
|
260
|
-
def clear_association_cache
|
|
261
|
-
@association_cache.clear if persisted?
|
|
262
|
-
end
|
|
263
|
-
|
|
264
75
|
def init_internals
|
|
265
|
-
@association_cache = {}
|
|
266
76
|
super
|
|
77
|
+
@association_cache = {}
|
|
267
78
|
end
|
|
268
79
|
|
|
269
80
|
# Returns the specified association instance if it exists, +nil+ otherwise.
|
|
@@ -276,6 +87,8 @@ module ActiveRecord
|
|
|
276
87
|
@association_cache[name] = association
|
|
277
88
|
end
|
|
278
89
|
|
|
90
|
+
# = Active Record \Associations
|
|
91
|
+
#
|
|
279
92
|
# \Associations are a set of macro-like class methods for tying objects together through
|
|
280
93
|
# foreign keys. They express relationships like "Project has one Project Manager"
|
|
281
94
|
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
|
|
@@ -292,23 +105,42 @@ module ActiveRecord
|
|
|
292
105
|
#
|
|
293
106
|
# The project class now has the following methods (and more) to ease the traversal and
|
|
294
107
|
# manipulation of its relationships:
|
|
295
|
-
#
|
|
296
|
-
#
|
|
297
|
-
#
|
|
298
|
-
#
|
|
299
|
-
#
|
|
300
|
-
#
|
|
301
|
-
#
|
|
108
|
+
#
|
|
109
|
+
# project = Project.first
|
|
110
|
+
# project.portfolio
|
|
111
|
+
# project.portfolio = Portfolio.first
|
|
112
|
+
# project.reload_portfolio
|
|
113
|
+
#
|
|
114
|
+
# project.project_manager
|
|
115
|
+
# project.project_manager = ProjectManager.first
|
|
116
|
+
# project.reload_project_manager
|
|
117
|
+
#
|
|
118
|
+
# project.milestones.empty?
|
|
119
|
+
# project.milestones.size
|
|
120
|
+
# project.milestones
|
|
121
|
+
# project.milestones << Milestone.first
|
|
122
|
+
# project.milestones.delete(Milestone.first)
|
|
123
|
+
# project.milestones.destroy(Milestone.first)
|
|
124
|
+
# project.milestones.find(Milestone.first.id)
|
|
125
|
+
# project.milestones.build
|
|
126
|
+
# project.milestones.create
|
|
127
|
+
#
|
|
128
|
+
# project.categories.empty?
|
|
129
|
+
# project.categories.size
|
|
130
|
+
# project.categories
|
|
131
|
+
# project.categories << Category.first
|
|
132
|
+
# project.categories.delete(category1)
|
|
133
|
+
# project.categories.destroy(category1)
|
|
302
134
|
#
|
|
303
135
|
# === A word of warning
|
|
304
136
|
#
|
|
305
137
|
# Don't create associations that have the same name as {instance methods}[rdoc-ref:ActiveRecord::Core] of
|
|
306
|
-
#
|
|
307
|
-
# its model, using an association with the same name as one provided by
|
|
308
|
-
# For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of
|
|
138
|
+
# +ActiveRecord::Base+. Since the association adds a method with that name to
|
|
139
|
+
# its model, using an association with the same name as one provided by +ActiveRecord::Base+ will override the method inherited through +ActiveRecord::Base+ and will break things.
|
|
140
|
+
# For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of +ActiveRecord::Base+ instance methods.
|
|
309
141
|
#
|
|
310
142
|
# == Auto-generated methods
|
|
311
|
-
# See also Instance Public methods below for more details.
|
|
143
|
+
# See also "Instance Public methods" below ( from #belongs_to ) for more details.
|
|
312
144
|
#
|
|
313
145
|
# === Singular associations (one-to-one)
|
|
314
146
|
# | | belongs_to |
|
|
@@ -320,6 +152,8 @@ module ActiveRecord
|
|
|
320
152
|
# create_other(attributes={}) | X | | X
|
|
321
153
|
# create_other!(attributes={}) | X | | X
|
|
322
154
|
# reload_other | X | X | X
|
|
155
|
+
# other_changed? | X | X |
|
|
156
|
+
# other_previously_changed? | X | X |
|
|
323
157
|
#
|
|
324
158
|
# === Collection associations (one-to-many / many-to-many)
|
|
325
159
|
# | | | has_many
|
|
@@ -373,7 +207,7 @@ module ActiveRecord
|
|
|
373
207
|
#
|
|
374
208
|
# == Cardinality and associations
|
|
375
209
|
#
|
|
376
|
-
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
|
|
210
|
+
# Active Record associations can be used to describe one-to-one, one-to-many, and many-to-many
|
|
377
211
|
# relationships between models. Each model uses an association to describe its role in
|
|
378
212
|
# the relation. The #belongs_to association is always used in the model that has
|
|
379
213
|
# the foreign key.
|
|
@@ -527,8 +361,11 @@ module ActiveRecord
|
|
|
527
361
|
# has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
|
|
528
362
|
# end
|
|
529
363
|
#
|
|
530
|
-
# Note: Joining
|
|
531
|
-
#
|
|
364
|
+
# Note: Joining or eager loading such associations is not possible because
|
|
365
|
+
# those operations happen before instance creation. Such associations
|
|
366
|
+
# _can_ be preloaded, but doing so will perform N+1 queries because there
|
|
367
|
+
# will be a different scope for each record (similar to preloading
|
|
368
|
+
# polymorphic scopes).
|
|
532
369
|
#
|
|
533
370
|
# == Association callbacks
|
|
534
371
|
#
|
|
@@ -536,22 +373,31 @@ module ActiveRecord
|
|
|
536
373
|
# you can also define callbacks that get triggered when you add an object to or remove an
|
|
537
374
|
# object from an association collection.
|
|
538
375
|
#
|
|
539
|
-
# class
|
|
540
|
-
#
|
|
376
|
+
# class Firm < ActiveRecord::Base
|
|
377
|
+
# has_many :clients,
|
|
378
|
+
# dependent: :destroy,
|
|
379
|
+
# after_add: :congratulate_client,
|
|
380
|
+
# after_remove: :log_after_remove
|
|
381
|
+
#
|
|
382
|
+
# def congratulate_client(record)
|
|
383
|
+
# # ...
|
|
384
|
+
# end
|
|
541
385
|
#
|
|
542
|
-
# def
|
|
543
|
-
# ...
|
|
386
|
+
# def log_after_remove(record)
|
|
387
|
+
# # ...
|
|
544
388
|
# end
|
|
545
389
|
# end
|
|
546
390
|
#
|
|
547
391
|
# It's possible to stack callbacks by passing them as an array. Example:
|
|
548
392
|
#
|
|
549
|
-
# class
|
|
550
|
-
#
|
|
551
|
-
#
|
|
393
|
+
# class Firm < ActiveRecord::Base
|
|
394
|
+
# has_many :clients,
|
|
395
|
+
# dependent: :destroy,
|
|
396
|
+
# after_add: [:congratulate_client, -> (firm, record) { firm.log << "after_adding#{record.id}" }],
|
|
397
|
+
# after_remove: :log_after_remove
|
|
552
398
|
# end
|
|
553
399
|
#
|
|
554
|
-
# Possible callbacks are: +before_add+, +after_add+, +before_remove
|
|
400
|
+
# Possible callbacks are: +before_add+, +after_add+, +before_remove+, and +after_remove+.
|
|
555
401
|
#
|
|
556
402
|
# If any of the +before_add+ callbacks throw an exception, the object will not be
|
|
557
403
|
# added to the collection.
|
|
@@ -559,6 +405,18 @@ module ActiveRecord
|
|
|
559
405
|
# Similarly, if any of the +before_remove+ callbacks throw an exception, the object
|
|
560
406
|
# will not be removed from the collection.
|
|
561
407
|
#
|
|
408
|
+
# Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
|
|
409
|
+
#
|
|
410
|
+
# * <tt>firm.clients.destroy(client)</tt>
|
|
411
|
+
# * <tt>firm.clients.destroy(*clients)</tt>
|
|
412
|
+
# * <tt>firm.clients.destroy_all</tt>
|
|
413
|
+
#
|
|
414
|
+
# +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
|
|
415
|
+
#
|
|
416
|
+
# * <tt>firm.clients.delete(client)</tt>
|
|
417
|
+
# * <tt>firm.clients.delete(*clients)</tt>
|
|
418
|
+
# * <tt>firm.clients.delete_all</tt>
|
|
419
|
+
#
|
|
562
420
|
# == Association extensions
|
|
563
421
|
#
|
|
564
422
|
# The proxy objects that control the access to associations can be extended through anonymous
|
|
@@ -679,7 +537,7 @@ module ActiveRecord
|
|
|
679
537
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
|
680
538
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
|
681
539
|
#
|
|
682
|
-
#
|
|
540
|
+
# === Setting Inverses
|
|
683
541
|
#
|
|
684
542
|
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
|
685
543
|
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
|
@@ -702,10 +560,10 @@ module ActiveRecord
|
|
|
702
560
|
# inverse detection only works on #has_many, #has_one, and
|
|
703
561
|
# #belongs_to associations.
|
|
704
562
|
#
|
|
705
|
-
#
|
|
706
|
-
#
|
|
707
|
-
#
|
|
708
|
-
#
|
|
563
|
+
# <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations
|
|
564
|
+
# will also prevent the association's inverse from being found automatically,
|
|
565
|
+
# as will a custom scopes in some cases. See further details in the
|
|
566
|
+
# {Active Record Associations guide}[https://guides.rubyonrails.org/association_basics.html#bi-directional-associations].
|
|
709
567
|
#
|
|
710
568
|
# The automatic guessing of the inverse association uses a heuristic based
|
|
711
569
|
# on the name of the class, so it may not work for all associations,
|
|
@@ -930,7 +788,7 @@ module ActiveRecord
|
|
|
930
788
|
# query per addressable type.
|
|
931
789
|
# For example, if all the addressables are either of class Person or Company, then a total
|
|
932
790
|
# of 3 queries will be executed. The list of addressable types to load is determined on
|
|
933
|
-
# the back of the addresses loaded. This is not supported if Active Record has to
|
|
791
|
+
# the back of the addresses loaded. This is not supported if Active Record has to fall back
|
|
934
792
|
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError.
|
|
935
793
|
# The reason is that the parent model's type is a column value so its corresponding table
|
|
936
794
|
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
|
|
@@ -943,45 +801,45 @@ module ActiveRecord
|
|
|
943
801
|
# Indexes are appended for any more successive uses of the table name.
|
|
944
802
|
#
|
|
945
803
|
# Post.joins(:comments)
|
|
946
|
-
# #
|
|
804
|
+
# # SELECT ... FROM posts INNER JOIN comments ON ...
|
|
947
805
|
# Post.joins(:special_comments) # STI
|
|
948
|
-
# #
|
|
806
|
+
# # SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
|
|
949
807
|
# Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name
|
|
950
|
-
# #
|
|
808
|
+
# # SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
|
|
951
809
|
#
|
|
952
810
|
# Acts as tree example:
|
|
953
811
|
#
|
|
954
812
|
# TreeMixin.joins(:children)
|
|
955
|
-
# #
|
|
813
|
+
# # SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
|
956
814
|
# TreeMixin.joins(children: :parent)
|
|
957
|
-
# #
|
|
958
|
-
#
|
|
815
|
+
# # SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
|
816
|
+
# # INNER JOIN parents_mixins ...
|
|
959
817
|
# TreeMixin.joins(children: {parent: :children})
|
|
960
|
-
# #
|
|
961
|
-
#
|
|
962
|
-
#
|
|
818
|
+
# # SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
|
819
|
+
# # INNER JOIN parents_mixins ...
|
|
820
|
+
# # INNER JOIN mixins childrens_mixins_2
|
|
963
821
|
#
|
|
964
822
|
# Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
|
|
965
823
|
#
|
|
966
824
|
# Post.joins(:categories)
|
|
967
|
-
# #
|
|
825
|
+
# # SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
|
968
826
|
# Post.joins(categories: :posts)
|
|
969
|
-
# #
|
|
970
|
-
#
|
|
827
|
+
# # SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
|
828
|
+
# # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
|
971
829
|
# Post.joins(categories: {posts: :categories})
|
|
972
|
-
# #
|
|
973
|
-
#
|
|
974
|
-
#
|
|
830
|
+
# # SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
|
831
|
+
# # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
|
832
|
+
# # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
|
|
975
833
|
#
|
|
976
834
|
# If you wish to specify your own custom joins using ActiveRecord::QueryMethods#joins method, those table
|
|
977
835
|
# names will take precedence over the eager associations:
|
|
978
836
|
#
|
|
979
837
|
# Post.joins(:comments).joins("inner join comments ...")
|
|
980
|
-
# #
|
|
838
|
+
# # SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
|
|
981
839
|
# Post.joins(:comments, :special_comments).joins("inner join comments ...")
|
|
982
|
-
# #
|
|
983
|
-
#
|
|
984
|
-
#
|
|
840
|
+
# # SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
|
|
841
|
+
# # INNER JOIN comments special_comments_posts ...
|
|
842
|
+
# # INNER JOIN comments ...
|
|
985
843
|
#
|
|
986
844
|
# Table aliases are automatically truncated according to the maximum length of table identifiers
|
|
987
845
|
# according to the specific database.
|
|
@@ -1062,7 +920,8 @@ module ActiveRecord
|
|
|
1062
920
|
# belongs_to :dungeon, inverse_of: :evil_wizard
|
|
1063
921
|
# end
|
|
1064
922
|
#
|
|
1065
|
-
# For more information, see the documentation for the +:inverse_of+ option
|
|
923
|
+
# For more information, see the documentation for the +:inverse_of+ option and the
|
|
924
|
+
# {Active Record Associations guide}[https://guides.rubyonrails.org/association_basics.html#bi-directional-associations].
|
|
1066
925
|
#
|
|
1067
926
|
# == Deleting from associations
|
|
1068
927
|
#
|
|
@@ -1084,7 +943,7 @@ module ActiveRecord
|
|
|
1084
943
|
# specific association types. When no option is given, the behavior is to do nothing
|
|
1085
944
|
# with the associated records when destroying a record.
|
|
1086
945
|
#
|
|
1087
|
-
# Note that <tt>:dependent</tt> is implemented using Rails' callback
|
|
946
|
+
# Note that <tt>:dependent</tt> is implemented using \Rails' callback
|
|
1088
947
|
# system, which works by processing callbacks in order. Therefore, other
|
|
1089
948
|
# callbacks declared either before or after the <tt>:dependent</tt> option
|
|
1090
949
|
# can affect what it does.
|
|
@@ -1155,15 +1014,15 @@ module ActiveRecord
|
|
|
1155
1014
|
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
|
1156
1015
|
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
|
|
1157
1016
|
#
|
|
1158
|
-
# [collection]
|
|
1017
|
+
# [<tt>collection</tt>]
|
|
1159
1018
|
# Returns a Relation of all the associated objects.
|
|
1160
1019
|
# An empty Relation is returned if none are found.
|
|
1161
|
-
# [collection<<(object, ...)]
|
|
1020
|
+
# [<tt>collection<<(object, ...)</tt>]
|
|
1162
1021
|
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
|
1163
1022
|
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
|
1164
1023
|
# parent object, unless the parent object is a new record.
|
|
1165
1024
|
# This will also run validations and callbacks of associated object(s).
|
|
1166
|
-
# [collection.delete(object, ...)]
|
|
1025
|
+
# [<tt>collection.delete(object, ...)</tt>]
|
|
1167
1026
|
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
|
|
1168
1027
|
# Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
|
|
1169
1028
|
# and deleted if they're associated with <tt>dependent: :delete_all</tt>.
|
|
@@ -1171,75 +1030,84 @@ module ActiveRecord
|
|
|
1171
1030
|
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than
|
|
1172
1031
|
# nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
|
|
1173
1032
|
# <tt>dependent: :nullify</tt> to override this.
|
|
1174
|
-
# [collection.destroy(object, ...)]
|
|
1033
|
+
# [<tt>collection.destroy(object, ...)</tt>]
|
|
1175
1034
|
# Removes one or more objects from the collection by running <tt>destroy</tt> on
|
|
1176
1035
|
# each record, regardless of any dependent option, ensuring callbacks are run.
|
|
1177
1036
|
#
|
|
1178
1037
|
# If the <tt>:through</tt> option is used, then the join records are destroyed
|
|
1179
1038
|
# instead, not the objects themselves.
|
|
1180
|
-
# [collection=objects]
|
|
1039
|
+
# [<tt>collection=objects</tt>]
|
|
1181
1040
|
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
|
|
1182
1041
|
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
|
|
1183
1042
|
# direct by default. You can specify <tt>dependent: :destroy</tt> or
|
|
1184
1043
|
# <tt>dependent: :nullify</tt> to override this.
|
|
1185
|
-
# [collection_singular_ids]
|
|
1044
|
+
# [<tt>collection_singular_ids</tt>]
|
|
1186
1045
|
# Returns an array of the associated objects' ids
|
|
1187
|
-
# [collection_singular_ids=ids]
|
|
1046
|
+
# [<tt>collection_singular_ids=ids</tt>]
|
|
1188
1047
|
# Replace the collection with the objects identified by the primary keys in +ids+. This
|
|
1189
1048
|
# method loads the models and calls <tt>collection=</tt>. See above.
|
|
1190
|
-
# [collection.clear]
|
|
1049
|
+
# [<tt>collection.clear</tt>]
|
|
1191
1050
|
# Removes every object from the collection. This destroys the associated objects if they
|
|
1192
1051
|
# are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
|
|
1193
1052
|
# database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
|
|
1194
1053
|
# If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
|
|
1195
1054
|
# Join models are directly deleted.
|
|
1196
|
-
# [collection.empty
|
|
1055
|
+
# [<tt>collection.empty?</tt>]
|
|
1197
1056
|
# Returns +true+ if there are no associated objects.
|
|
1198
|
-
# [collection.size]
|
|
1057
|
+
# [<tt>collection.size</tt>]
|
|
1199
1058
|
# Returns the number of associated objects.
|
|
1200
|
-
# [collection.find(...)]
|
|
1059
|
+
# [<tt>collection.find(...)</tt>]
|
|
1201
1060
|
# Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find.
|
|
1202
|
-
# [collection.exists?(...)]
|
|
1061
|
+
# [<tt>collection.exists?(...)</tt>]
|
|
1203
1062
|
# Checks whether an associated object with the given conditions exists.
|
|
1204
1063
|
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
|
|
1205
|
-
# [collection.build(attributes = {}, ...)]
|
|
1064
|
+
# [<tt>collection.build(attributes = {}, ...)</tt>]
|
|
1206
1065
|
# Returns one or more new objects of the collection type that have been instantiated
|
|
1207
1066
|
# with +attributes+ and linked to this object through a foreign key, but have not yet
|
|
1208
1067
|
# been saved.
|
|
1209
|
-
# [collection.create(attributes = {})]
|
|
1068
|
+
# [<tt>collection.create(attributes = {})</tt>]
|
|
1210
1069
|
# Returns a new object of the collection type that has been instantiated
|
|
1211
1070
|
# with +attributes+, linked to this object through a foreign key, and that has already
|
|
1212
1071
|
# been saved (if it passed the validation). *Note*: This only works if the base model
|
|
1213
1072
|
# already exists in the DB, not if it is a new (unsaved) record!
|
|
1214
|
-
# [collection.create!(attributes = {})]
|
|
1073
|
+
# [<tt>collection.create!(attributes = {})</tt>]
|
|
1215
1074
|
# Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
|
|
1216
1075
|
# if the record is invalid.
|
|
1217
|
-
# [collection.reload]
|
|
1076
|
+
# [<tt>collection.reload</tt>]
|
|
1218
1077
|
# Returns a Relation of all of the associated objects, forcing a database read.
|
|
1219
1078
|
# An empty Relation is returned if none are found.
|
|
1220
1079
|
#
|
|
1221
|
-
#
|
|
1222
|
-
#
|
|
1223
|
-
#
|
|
1224
|
-
#
|
|
1225
|
-
#
|
|
1226
|
-
#
|
|
1227
|
-
#
|
|
1228
|
-
#
|
|
1229
|
-
#
|
|
1230
|
-
#
|
|
1231
|
-
#
|
|
1232
|
-
#
|
|
1233
|
-
#
|
|
1234
|
-
#
|
|
1235
|
-
#
|
|
1236
|
-
#
|
|
1237
|
-
#
|
|
1238
|
-
#
|
|
1239
|
-
#
|
|
1080
|
+
# ==== Example
|
|
1081
|
+
#
|
|
1082
|
+
# class Firm < ActiveRecord::Base
|
|
1083
|
+
# has_many :clients
|
|
1084
|
+
# end
|
|
1085
|
+
#
|
|
1086
|
+
# Declaring <tt>has_many :clients</tt> adds the following methods (and more):
|
|
1087
|
+
#
|
|
1088
|
+
# firm = Firm.find(2)
|
|
1089
|
+
# client = Client.find(6)
|
|
1090
|
+
#
|
|
1091
|
+
# firm.clients # similar to Client.where(firm_id: 2)
|
|
1092
|
+
# firm.clients << client
|
|
1093
|
+
# firm.clients.delete(client)
|
|
1094
|
+
# firm.clients.destroy(client)
|
|
1095
|
+
# firm.clients = [client]
|
|
1096
|
+
# firm.client_ids
|
|
1097
|
+
# firm.client_ids = [6]
|
|
1098
|
+
# firm.clients.clear
|
|
1099
|
+
# firm.clients.empty? # similar to firm.clients.size == 0
|
|
1100
|
+
# firm.clients.size # similar to Client.count "firm_id = 2"
|
|
1101
|
+
# firm.clients.find # similar to Client.where(firm_id: 2).find(6)
|
|
1102
|
+
# firm.clients.exists?(name: 'ACME') # similar to Client.exists?(name: 'ACME', firm_id: 2)
|
|
1103
|
+
# firm.clients.build # similar to Client.new(firm_id: 2)
|
|
1104
|
+
# firm.clients.create # similar to Client.create(firm_id: 2)
|
|
1105
|
+
# firm.clients.create! # similar to Client.create!(firm_id: 2)
|
|
1106
|
+
# firm.clients.reload
|
|
1107
|
+
#
|
|
1240
1108
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1241
1109
|
#
|
|
1242
|
-
#
|
|
1110
|
+
# ==== Scopes
|
|
1243
1111
|
#
|
|
1244
1112
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1245
1113
|
# lambda) to retrieve a specific set of records or customize the generated
|
|
@@ -1250,10 +1118,10 @@ module ActiveRecord
|
|
|
1250
1118
|
# has_many :employees, -> { joins(:address) }
|
|
1251
1119
|
# has_many :posts, ->(blog) { where("max_post_length > ?", blog.max_post_length) }
|
|
1252
1120
|
#
|
|
1253
|
-
#
|
|
1121
|
+
# ==== Extensions
|
|
1254
1122
|
#
|
|
1255
1123
|
# The +extension+ argument allows you to pass a block into a has_many
|
|
1256
|
-
# association. This is useful for adding new finders, creators and other
|
|
1124
|
+
# association. This is useful for adding new finders, creators, and other
|
|
1257
1125
|
# factory-type methods to be used as part of the association.
|
|
1258
1126
|
#
|
|
1259
1127
|
# Extension examples:
|
|
@@ -1264,39 +1132,43 @@ module ActiveRecord
|
|
|
1264
1132
|
# end
|
|
1265
1133
|
# end
|
|
1266
1134
|
#
|
|
1267
|
-
#
|
|
1268
|
-
# [
|
|
1135
|
+
# ==== Options
|
|
1136
|
+
# [+:class_name+]
|
|
1269
1137
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1270
1138
|
# from the association name. So <tt>has_many :products</tt> will by default be linked
|
|
1271
1139
|
# to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to
|
|
1272
1140
|
# specify it with this option.
|
|
1273
|
-
# [
|
|
1141
|
+
# [+:foreign_key+]
|
|
1274
1142
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1275
1143
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many
|
|
1276
1144
|
# association will use "person_id" as the default <tt>:foreign_key</tt>.
|
|
1277
1145
|
#
|
|
1278
|
-
#
|
|
1279
|
-
# a good idea to set the <tt>:inverse_of</tt> option.
|
|
1280
|
-
# [
|
|
1146
|
+
# Setting the <tt>:foreign_key</tt> option prevents automatic detection of the association's
|
|
1147
|
+
# inverse, so it is generally a good idea to set the <tt>:inverse_of</tt> option as well.
|
|
1148
|
+
# [+:foreign_type+]
|
|
1281
1149
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
|
1282
1150
|
# association. By default this is guessed to be the name of the polymorphic association
|
|
1283
1151
|
# specified on "as" option with a "_type" suffix. So a class that defines a
|
|
1284
1152
|
# <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
|
|
1285
1153
|
# default <tt>:foreign_type</tt>.
|
|
1286
|
-
# [
|
|
1154
|
+
# [+:primary_key+]
|
|
1287
1155
|
# Specify the name of the column to use as the primary key for the association. By default this is +id+.
|
|
1288
|
-
# [
|
|
1156
|
+
# [+:dependent+]
|
|
1289
1157
|
# Controls what happens to the associated objects when
|
|
1290
1158
|
# their owner is destroyed. Note that these are implemented as
|
|
1291
|
-
# callbacks, and Rails executes callbacks in order. Therefore, other
|
|
1159
|
+
# callbacks, and \Rails executes callbacks in order. Therefore, other
|
|
1292
1160
|
# similar callbacks may affect the <tt>:dependent</tt> behavior, and the
|
|
1293
1161
|
# <tt>:dependent</tt> behavior may affect other callbacks.
|
|
1294
1162
|
#
|
|
1163
|
+
# * <tt>nil</tt> do nothing (default).
|
|
1295
1164
|
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
|
1165
|
+
# * <tt>:destroy_async</tt> destroys all the associated objects in a background job. <b>WARNING:</b> Do not use
|
|
1166
|
+
# this option if the association is backed by foreign key constraints in your database. The foreign key
|
|
1167
|
+
# constraint actions will occur inside the same transaction that deletes its owner.
|
|
1296
1168
|
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
|
1297
1169
|
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
|
|
1298
1170
|
# on polymorphic associations. Callbacks are not executed.
|
|
1299
|
-
# * <tt>:restrict_with_exception</tt> causes an
|
|
1171
|
+
# * <tt>:restrict_with_exception</tt> causes an ActiveRecord::DeleteRestrictionError exception to be raised if there are any associated records.
|
|
1300
1172
|
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
|
|
1301
1173
|
#
|
|
1302
1174
|
# If using with the <tt>:through</tt> option, the association on the join model must be
|
|
@@ -1308,12 +1180,12 @@ module ActiveRecord
|
|
|
1308
1180
|
# <tt>has_many :comments, -> { where published: true }, dependent: :destroy</tt> and <tt>destroy</tt> is
|
|
1309
1181
|
# called on a post, only published comments are destroyed. This means that any unpublished comments in the
|
|
1310
1182
|
# database would still contain a foreign key pointing to the now deleted post.
|
|
1311
|
-
# [
|
|
1183
|
+
# [+:counter_cache+]
|
|
1312
1184
|
# This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
|
|
1313
1185
|
# when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
|
|
1314
|
-
# [
|
|
1186
|
+
# [+:as+]
|
|
1315
1187
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1316
|
-
# [
|
|
1188
|
+
# [+:through+]
|
|
1317
1189
|
# Specifies an association through which to perform the query. This can be any other type
|
|
1318
1190
|
# of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
|
|
1319
1191
|
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
|
|
@@ -1327,20 +1199,28 @@ module ActiveRecord
|
|
|
1327
1199
|
# If you are going to modify the association (rather than just read from it), then it is
|
|
1328
1200
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
|
1329
1201
|
# join model. This allows associated records to be built which will automatically create
|
|
1330
|
-
# the appropriate join model records when they are saved.
|
|
1331
|
-
#
|
|
1332
|
-
# [:
|
|
1202
|
+
# the appropriate join model records when they are saved. See
|
|
1203
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
|
1204
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
|
1205
|
+
# more detail.
|
|
1206
|
+
#
|
|
1207
|
+
# [+:disable_joins+]
|
|
1208
|
+
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
|
1209
|
+
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
|
1210
|
+
# due to database limitations. This option is only applicable on <tt>has_many :through</tt> associations as
|
|
1211
|
+
# +has_many+ alone do not perform a join.
|
|
1212
|
+
# [+:source+]
|
|
1333
1213
|
# Specifies the source association name used by #has_many <tt>:through</tt> queries.
|
|
1334
1214
|
# Only use it if the name cannot be inferred from the association.
|
|
1335
1215
|
# <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
|
|
1336
1216
|
# <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
|
|
1337
|
-
# [
|
|
1217
|
+
# [+:source_type+]
|
|
1338
1218
|
# Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source
|
|
1339
1219
|
# association is a polymorphic #belongs_to.
|
|
1340
|
-
# [
|
|
1220
|
+
# [+:validate+]
|
|
1341
1221
|
# When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
|
|
1342
1222
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
1343
|
-
# [
|
|
1223
|
+
# [+:autosave+]
|
|
1344
1224
|
# If true, always save the associated objects or destroy them if marked for destruction,
|
|
1345
1225
|
# when saving the parent object. If false, never save or destroy the associated objects.
|
|
1346
1226
|
# By default, only save associated objects that are new records. This option is implemented as a
|
|
@@ -1349,14 +1229,32 @@ module ActiveRecord
|
|
|
1349
1229
|
#
|
|
1350
1230
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
|
1351
1231
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
1352
|
-
# [
|
|
1232
|
+
# [+:inverse_of+]
|
|
1353
1233
|
# Specifies the name of the #belongs_to association on the associated object
|
|
1354
1234
|
# that is the inverse of this #has_many association.
|
|
1355
|
-
# See
|
|
1356
|
-
#
|
|
1235
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1236
|
+
# for more detail.
|
|
1237
|
+
# [+:extend+]
|
|
1357
1238
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
|
1358
1239
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
|
1359
1240
|
# association objects.
|
|
1241
|
+
# [+:strict_loading+]
|
|
1242
|
+
# When set to +true+, enforces strict loading every time the associated record is loaded through this
|
|
1243
|
+
# association.
|
|
1244
|
+
# [+:ensuring_owner_was+]
|
|
1245
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
|
1246
|
+
# associated records to be deleted in a background job.
|
|
1247
|
+
# [+:query_constraints+]
|
|
1248
|
+
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1249
|
+
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1250
|
+
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1251
|
+
# [+:index_errors+]
|
|
1252
|
+
# Allows differentiation of multiple validation errors from the association records, by including
|
|
1253
|
+
# an index in the error attribute name, e.g. +roles[2].level+.
|
|
1254
|
+
# When set to +true+, the index is based on association order, i.e. database order, with yet to be
|
|
1255
|
+
# persisted new records placed at the end.
|
|
1256
|
+
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
|
1257
|
+
# nested attributes setter, when accepts_nested_attributes_for is used.
|
|
1360
1258
|
#
|
|
1361
1259
|
# Option examples:
|
|
1362
1260
|
# has_many :comments, -> { order("posted_on") }
|
|
@@ -1367,52 +1265,69 @@ module ActiveRecord
|
|
|
1367
1265
|
# has_many :tags, as: :taggable
|
|
1368
1266
|
# has_many :reports, -> { readonly }
|
|
1369
1267
|
# has_many :subscribers, through: :subscriptions, source: :user
|
|
1268
|
+
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
|
1269
|
+
# has_many :comments, strict_loading: true
|
|
1270
|
+
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
|
1271
|
+
# has_many :comments, index_errors: :nested_attributes_order
|
|
1370
1272
|
def has_many(name, scope = nil, **options, &extension)
|
|
1371
1273
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
|
1372
1274
|
Reflection.add_reflection self, name, reflection
|
|
1373
1275
|
end
|
|
1374
1276
|
|
|
1375
|
-
# Specifies a one-to-one association with another class. This method
|
|
1376
|
-
# if the other class contains the foreign key. If
|
|
1377
|
-
#
|
|
1378
|
-
#
|
|
1277
|
+
# Specifies a one-to-one association with another class. This method
|
|
1278
|
+
# should only be used if the other class contains the foreign key. If
|
|
1279
|
+
# the current class contains the foreign key, then you should use
|
|
1280
|
+
# #belongs_to instead. See {Is it a belongs_to or has_one
|
|
1281
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
|
1282
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
|
1379
1283
|
#
|
|
1380
1284
|
# The following methods for retrieval and query of a single associated object will be added:
|
|
1381
1285
|
#
|
|
1382
1286
|
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
|
1383
1287
|
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
|
|
1384
1288
|
#
|
|
1385
|
-
# [association]
|
|
1289
|
+
# [<tt>association</tt>]
|
|
1386
1290
|
# Returns the associated object. +nil+ is returned if none is found.
|
|
1387
|
-
# [association=(associate)]
|
|
1291
|
+
# [<tt>association=(associate)</tt>]
|
|
1388
1292
|
# Assigns the associate object, extracts the primary key, sets it as the foreign key,
|
|
1389
1293
|
# and saves the associate object. To avoid database inconsistencies, permanently deletes an existing
|
|
1390
1294
|
# associated object when assigning a new one, even if the new one isn't saved to database.
|
|
1391
|
-
# [build_association(attributes = {})]
|
|
1295
|
+
# [<tt>build_association(attributes = {})</tt>]
|
|
1392
1296
|
# Returns a new object of the associated type that has been instantiated
|
|
1393
1297
|
# with +attributes+ and linked to this object through a foreign key, but has not
|
|
1394
1298
|
# yet been saved.
|
|
1395
|
-
# [create_association(attributes = {})]
|
|
1299
|
+
# [<tt>create_association(attributes = {})</tt>]
|
|
1396
1300
|
# Returns a new object of the associated type that has been instantiated
|
|
1397
1301
|
# with +attributes+, linked to this object through a foreign key, and that
|
|
1398
1302
|
# has already been saved (if it passed the validation).
|
|
1399
|
-
# [create_association!(attributes = {})]
|
|
1303
|
+
# [<tt>create_association!(attributes = {})</tt>]
|
|
1400
1304
|
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
|
1401
1305
|
# if the record is invalid.
|
|
1402
|
-
# [reload_association]
|
|
1306
|
+
# [<tt>reload_association</tt>]
|
|
1403
1307
|
# Returns the associated object, forcing a database read.
|
|
1308
|
+
# [<tt>reset_association</tt>]
|
|
1309
|
+
# Unloads the associated object. The next access will query it from the database.
|
|
1310
|
+
#
|
|
1311
|
+
# ==== Example
|
|
1404
1312
|
#
|
|
1405
|
-
#
|
|
1313
|
+
# class Account < ActiveRecord::Base
|
|
1314
|
+
# has_one :beneficiary
|
|
1315
|
+
# end
|
|
1406
1316
|
#
|
|
1407
|
-
#
|
|
1408
|
-
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
|
1409
|
-
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
|
1410
|
-
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new(account_id: id)</tt>)
|
|
1411
|
-
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save; b</tt>)
|
|
1412
|
-
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new(account_id: id); b.save!; b</tt>)
|
|
1413
|
-
# * <tt>Account#reload_beneficiary</tt>
|
|
1317
|
+
# Declaring <tt>has_one :beneficiary</tt> adds the following methods (and more):
|
|
1414
1318
|
#
|
|
1415
|
-
#
|
|
1319
|
+
# account = Account.find(5)
|
|
1320
|
+
# beneficiary = Beneficiary.find(8)
|
|
1321
|
+
#
|
|
1322
|
+
# account.beneficiary # similar to Beneficiary.find_by(account_id: 5)
|
|
1323
|
+
# account.beneficiary = beneficiary # similar to beneficiary.update(account_id: 5)
|
|
1324
|
+
# account.build_beneficiary # similar to Beneficiary.new(account_id: 5)
|
|
1325
|
+
# account.create_beneficiary # similar to Beneficiary.create(account_id: 5)
|
|
1326
|
+
# account.create_beneficiary! # similar to Beneficiary.create!(account_id: 5)
|
|
1327
|
+
# account.reload_beneficiary
|
|
1328
|
+
# account.reset_beneficiary
|
|
1329
|
+
#
|
|
1330
|
+
# ==== Scopes
|
|
1416
1331
|
#
|
|
1417
1332
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1418
1333
|
# lambda) to retrieve a specific record or customize the generated query
|
|
@@ -1423,78 +1338,118 @@ module ActiveRecord
|
|
|
1423
1338
|
# has_one :employer, -> { joins(:company) }
|
|
1424
1339
|
# has_one :latest_post, ->(blog) { where("created_at > ?", blog.enabled_at) }
|
|
1425
1340
|
#
|
|
1426
|
-
#
|
|
1341
|
+
# ==== Options
|
|
1427
1342
|
#
|
|
1428
1343
|
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1429
1344
|
#
|
|
1430
1345
|
# Options are:
|
|
1431
|
-
# [
|
|
1346
|
+
# [+:class_name+]
|
|
1432
1347
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1433
1348
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
|
|
1434
1349
|
# if the real class name is Person, you'll have to specify it with this option.
|
|
1435
|
-
# [
|
|
1350
|
+
# [+:dependent+]
|
|
1436
1351
|
# Controls what happens to the associated object when
|
|
1437
1352
|
# its owner is destroyed:
|
|
1438
1353
|
#
|
|
1354
|
+
# * <tt>nil</tt> do nothing (default).
|
|
1439
1355
|
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
|
1356
|
+
# * <tt>:destroy_async</tt> causes the associated object to be destroyed in a background job. <b>WARNING:</b> Do not use
|
|
1357
|
+
# this option if the association is backed by foreign key constraints in your database. The foreign key
|
|
1358
|
+
# constraint actions will occur inside the same transaction that deletes its owner.
|
|
1440
1359
|
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
|
1441
1360
|
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
|
|
1442
1361
|
# on polymorphic associations. Callbacks are not executed.
|
|
1443
|
-
# * <tt>:restrict_with_exception</tt> causes an
|
|
1362
|
+
# * <tt>:restrict_with_exception</tt> causes an ActiveRecord::DeleteRestrictionError exception to be raised if there is an associated record
|
|
1444
1363
|
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
|
|
1445
1364
|
#
|
|
1446
1365
|
# Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
|
|
1447
|
-
# [
|
|
1366
|
+
# [+:foreign_key+]
|
|
1448
1367
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1449
1368
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association
|
|
1450
1369
|
# will use "person_id" as the default <tt>:foreign_key</tt>.
|
|
1451
1370
|
#
|
|
1452
|
-
#
|
|
1453
|
-
# a good idea to set the <tt>:inverse_of</tt> option.
|
|
1454
|
-
# [
|
|
1371
|
+
# Setting the <tt>:foreign_key</tt> option prevents automatic detection of the association's
|
|
1372
|
+
# inverse, so it is generally a good idea to set the <tt>:inverse_of</tt> option as well.
|
|
1373
|
+
# [+:foreign_type+]
|
|
1455
1374
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
|
1456
1375
|
# association. By default this is guessed to be the name of the polymorphic association
|
|
1457
1376
|
# specified on "as" option with a "_type" suffix. So a class that defines a
|
|
1458
1377
|
# <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
|
|
1459
1378
|
# default <tt>:foreign_type</tt>.
|
|
1460
|
-
# [
|
|
1379
|
+
# [+:primary_key+]
|
|
1461
1380
|
# Specify the method that returns the primary key used for the association. By default this is +id+.
|
|
1462
|
-
# [
|
|
1381
|
+
# [+:as+]
|
|
1463
1382
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1464
|
-
# [
|
|
1383
|
+
# [+:through+]
|
|
1465
1384
|
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
|
|
1466
1385
|
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
|
|
1467
1386
|
# source reflection. You can only use a <tt>:through</tt> query through a #has_one
|
|
1468
1387
|
# or #belongs_to association on the join model.
|
|
1469
1388
|
#
|
|
1389
|
+
# If the association on the join model is a #belongs_to, the collection can be modified
|
|
1390
|
+
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
|
1391
|
+
# as appropriate. Otherwise, the collection is read-only, so you should manipulate the
|
|
1392
|
+
# <tt>:through</tt> association directly.
|
|
1393
|
+
#
|
|
1470
1394
|
# If you are going to modify the association (rather than just read from it), then it is
|
|
1471
|
-
# a good idea to set the <tt>:inverse_of</tt> option
|
|
1472
|
-
#
|
|
1395
|
+
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
|
1396
|
+
# join model. This allows associated records to be built which will automatically create
|
|
1397
|
+
# the appropriate join model records when they are saved. See
|
|
1398
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
|
1399
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
|
1400
|
+
# more detail.
|
|
1401
|
+
# [+:disable_joins+]
|
|
1402
|
+
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
|
1403
|
+
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
|
1404
|
+
# due to database limitations. This option is only applicable on <tt>has_one :through</tt> associations as
|
|
1405
|
+
# +has_one+ alone does not perform a join.
|
|
1406
|
+
# [+:source+]
|
|
1473
1407
|
# Specifies the source association name used by #has_one <tt>:through</tt> queries.
|
|
1474
1408
|
# Only use it if the name cannot be inferred from the association.
|
|
1475
1409
|
# <tt>has_one :favorite, through: :favorites</tt> will look for a
|
|
1476
1410
|
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
|
|
1477
|
-
# [
|
|
1411
|
+
# [+:source_type+]
|
|
1478
1412
|
# Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source
|
|
1479
1413
|
# association is a polymorphic #belongs_to.
|
|
1480
|
-
# [
|
|
1414
|
+
# [+:validate+]
|
|
1481
1415
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
|
1482
1416
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
1483
|
-
# [
|
|
1484
|
-
# If true
|
|
1485
|
-
# when saving the parent object.
|
|
1486
|
-
#
|
|
1417
|
+
# [+:autosave+]
|
|
1418
|
+
# If +true+, always saves the associated object or destroys it if marked for destruction,
|
|
1419
|
+
# when saving the parent object.
|
|
1420
|
+
# If +false+, never save or destroy the associated object.
|
|
1421
|
+
#
|
|
1422
|
+
# By default, only saves the associated object if it's a new record. Setting this option
|
|
1423
|
+
# to +true+ also enables validations on the associated object unless explicitly disabled
|
|
1424
|
+
# with <tt>validate: false</tt>. This is because saving an object with invalid associated
|
|
1425
|
+
# objects would fail, so any associated objects will go through validation checks.
|
|
1487
1426
|
#
|
|
1488
1427
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
|
1489
1428
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
1490
|
-
# [
|
|
1429
|
+
# [+:touch+]
|
|
1430
|
+
# If true, the associated object will be touched (the +updated_at+ / +updated_on+ attributes set to current time)
|
|
1431
|
+
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
|
1432
|
+
# will be updated with the current time in addition to the +updated_at+ / +updated_on+ attribute.
|
|
1433
|
+
# Please note that no validation will be performed when touching, and only the +after_touch+,
|
|
1434
|
+
# +after_commit+, and +after_rollback+ callbacks will be executed.
|
|
1435
|
+
# [+:inverse_of+]
|
|
1491
1436
|
# Specifies the name of the #belongs_to association on the associated object
|
|
1492
1437
|
# that is the inverse of this #has_one association.
|
|
1493
|
-
# See
|
|
1494
|
-
#
|
|
1438
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1439
|
+
# for more detail.
|
|
1440
|
+
# [+:required+]
|
|
1495
1441
|
# When set to +true+, the association will also have its presence validated.
|
|
1496
1442
|
# This will validate the association itself, not the id. You can use
|
|
1497
1443
|
# +:inverse_of+ to avoid an extra query during validation.
|
|
1444
|
+
# [+:strict_loading+]
|
|
1445
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
|
1446
|
+
# [+:ensuring_owner_was+]
|
|
1447
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
|
1448
|
+
# associated records to be deleted in a background job.
|
|
1449
|
+
# [+:query_constraints+]
|
|
1450
|
+
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1451
|
+
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1452
|
+
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1498
1453
|
#
|
|
1499
1454
|
# Option examples:
|
|
1500
1455
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
|
@@ -1505,17 +1460,22 @@ module ActiveRecord
|
|
|
1505
1460
|
# has_one :attachment, as: :attachable
|
|
1506
1461
|
# has_one :boss, -> { readonly }
|
|
1507
1462
|
# has_one :club, through: :membership
|
|
1463
|
+
# has_one :club, through: :membership, disable_joins: true
|
|
1508
1464
|
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
|
|
1509
1465
|
# has_one :credit_card, required: true
|
|
1466
|
+
# has_one :credit_card, strict_loading: true
|
|
1467
|
+
# has_one :employment_record_book, query_constraints: [:organization_id, :employee_id]
|
|
1510
1468
|
def has_one(name, scope = nil, **options)
|
|
1511
1469
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
|
1512
1470
|
Reflection.add_reflection self, name, reflection
|
|
1513
1471
|
end
|
|
1514
1472
|
|
|
1515
|
-
# Specifies a one-to-one association with another class. This method
|
|
1516
|
-
# if this class contains the foreign key. If the
|
|
1517
|
-
# then you should use #has_one
|
|
1518
|
-
#
|
|
1473
|
+
# Specifies a one-to-one association with another class. This method
|
|
1474
|
+
# should only be used if this class contains the foreign key. If the
|
|
1475
|
+
# other class contains the foreign key, then you should use #has_one
|
|
1476
|
+
# instead. See {Is it a belongs_to or has_one
|
|
1477
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
|
1478
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
|
1519
1479
|
#
|
|
1520
1480
|
# Methods will be added for retrieval and query for a single associated object, for which
|
|
1521
1481
|
# this object holds an id:
|
|
@@ -1523,36 +1483,52 @@ module ActiveRecord
|
|
|
1523
1483
|
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
|
1524
1484
|
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
|
|
1525
1485
|
#
|
|
1526
|
-
# [association]
|
|
1486
|
+
# [<tt>association</tt>]
|
|
1527
1487
|
# Returns the associated object. +nil+ is returned if none is found.
|
|
1528
|
-
# [association=(associate)]
|
|
1488
|
+
# [<tt>association=(associate)</tt>]
|
|
1529
1489
|
# Assigns the associate object, extracts the primary key, and sets it as the foreign key.
|
|
1530
1490
|
# No modification or deletion of existing records takes place.
|
|
1531
|
-
# [build_association(attributes = {})]
|
|
1491
|
+
# [<tt>build_association(attributes = {})</tt>]
|
|
1532
1492
|
# Returns a new object of the associated type that has been instantiated
|
|
1533
1493
|
# with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
|
|
1534
|
-
# [create_association(attributes = {})]
|
|
1494
|
+
# [<tt>create_association(attributes = {})</tt>]
|
|
1535
1495
|
# Returns a new object of the associated type that has been instantiated
|
|
1536
1496
|
# with +attributes+, linked to this object through a foreign key, and that
|
|
1537
1497
|
# has already been saved (if it passed the validation).
|
|
1538
|
-
# [create_association!(attributes = {})]
|
|
1498
|
+
# [<tt>create_association!(attributes = {})</tt>]
|
|
1539
1499
|
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
|
1540
1500
|
# if the record is invalid.
|
|
1541
|
-
# [reload_association]
|
|
1501
|
+
# [<tt>reload_association</tt>]
|
|
1542
1502
|
# Returns the associated object, forcing a database read.
|
|
1503
|
+
# [<tt>reset_association</tt>]
|
|
1504
|
+
# Unloads the associated object. The next access will query it from the database.
|
|
1505
|
+
# [<tt>association_changed?</tt>]
|
|
1506
|
+
# Returns true if a new associate object has been assigned and the next save will update the foreign key.
|
|
1507
|
+
# [<tt>association_previously_changed?</tt>]
|
|
1508
|
+
# Returns true if the previous save updated the association to reference a new associate object.
|
|
1543
1509
|
#
|
|
1544
|
-
#
|
|
1510
|
+
# ==== Example
|
|
1545
1511
|
#
|
|
1546
|
-
#
|
|
1547
|
-
#
|
|
1548
|
-
#
|
|
1549
|
-
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
|
1550
|
-
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
|
1551
|
-
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
|
1552
|
-
# * <tt>Post#reload_author</tt>
|
|
1553
|
-
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1512
|
+
# class Post < ActiveRecord::Base
|
|
1513
|
+
# belongs_to :author
|
|
1514
|
+
# end
|
|
1554
1515
|
#
|
|
1555
|
-
#
|
|
1516
|
+
# Declaring <tt>belongs_to :author</tt> adds the following methods (and more):
|
|
1517
|
+
#
|
|
1518
|
+
# post = Post.find(7)
|
|
1519
|
+
# author = Author.find(19)
|
|
1520
|
+
#
|
|
1521
|
+
# post.author # similar to Author.find(post.author_id)
|
|
1522
|
+
# post.author = author # similar to post.author_id = author.id
|
|
1523
|
+
# post.build_author # similar to post.author = Author.new
|
|
1524
|
+
# post.create_author # similar to post.author = Author.new; post.author.save; post.author
|
|
1525
|
+
# post.create_author! # similar to post.author = Author.new; post.author.save!; post.author
|
|
1526
|
+
# post.reload_author
|
|
1527
|
+
# post.reset_author
|
|
1528
|
+
# post.author_changed?
|
|
1529
|
+
# post.author_previously_changed?
|
|
1530
|
+
#
|
|
1531
|
+
# ==== Scopes
|
|
1556
1532
|
#
|
|
1557
1533
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1558
1534
|
# lambda) to retrieve a specific record or customize the generated query
|
|
@@ -1563,55 +1539,68 @@ module ActiveRecord
|
|
|
1563
1539
|
# belongs_to :user, -> { joins(:friends) }
|
|
1564
1540
|
# belongs_to :level, ->(game) { where("game_level > ?", game.current_level) }
|
|
1565
1541
|
#
|
|
1566
|
-
#
|
|
1542
|
+
# ==== Options
|
|
1543
|
+
#
|
|
1544
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
|
1567
1545
|
#
|
|
1568
|
-
# [
|
|
1546
|
+
# [+:class_name+]
|
|
1569
1547
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1570
1548
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
|
1571
1549
|
# if the real class name is Person, you'll have to specify it with this option.
|
|
1572
|
-
# [
|
|
1550
|
+
# [+:foreign_key+]
|
|
1573
1551
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1574
1552
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
|
1575
1553
|
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
|
|
1576
1554
|
# <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
|
|
1577
1555
|
# of "favorite_person_id".
|
|
1578
1556
|
#
|
|
1579
|
-
#
|
|
1580
|
-
# a good idea to set the <tt>:inverse_of</tt> option.
|
|
1581
|
-
# [
|
|
1557
|
+
# Setting the <tt>:foreign_key</tt> option prevents automatic detection of the association's
|
|
1558
|
+
# inverse, so it is generally a good idea to set the <tt>:inverse_of</tt> option as well.
|
|
1559
|
+
# [+:foreign_type+]
|
|
1582
1560
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
|
1583
1561
|
# association. By default this is guessed to be the name of the association with a "_type"
|
|
1584
1562
|
# suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
|
|
1585
1563
|
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
|
|
1586
|
-
# [
|
|
1564
|
+
# [+:primary_key+]
|
|
1587
1565
|
# Specify the method that returns the primary key of associated object used for the association.
|
|
1588
1566
|
# By default this is +id+.
|
|
1589
|
-
# [
|
|
1567
|
+
# [+:dependent+]
|
|
1590
1568
|
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
|
|
1591
|
-
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
|
|
1569
|
+
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to
|
|
1570
|
+
# <tt>:destroy_async</tt>, the associated object is scheduled to be destroyed in a background job.
|
|
1592
1571
|
# This option should not be specified when #belongs_to is used in conjunction with
|
|
1593
1572
|
# a #has_many relationship on another class because of the potential to leave
|
|
1594
1573
|
# orphaned records behind.
|
|
1595
|
-
# [
|
|
1574
|
+
# [+:counter_cache+]
|
|
1596
1575
|
# Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter
|
|
1597
1576
|
# and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this
|
|
1598
1577
|
# class is created and decremented when it's destroyed. This requires that a column
|
|
1599
1578
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
|
1600
1579
|
# is used on the associate class (such as a Post class) - that is the migration for
|
|
1601
1580
|
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
|
1602
|
-
# return the count cached
|
|
1581
|
+
# return the count cached). You can also specify a custom counter
|
|
1603
1582
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
|
1604
1583
|
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
|
1605
|
-
#
|
|
1606
|
-
#
|
|
1607
|
-
#
|
|
1608
|
-
#
|
|
1584
|
+
#
|
|
1585
|
+
# Starting to use counter caches on existing large tables can be troublesome, because the column
|
|
1586
|
+
# values must be backfilled separately of the column addition (to not lock the table for too long)
|
|
1587
|
+
# and before the use of +:counter_cache+ (otherwise methods like +size+/+any?+/etc, which use
|
|
1588
|
+
# counter caches internally, can produce incorrect results). To safely backfill the values while keeping
|
|
1589
|
+
# counter cache columns updated with the child records creation/removal and to avoid the mentioned methods
|
|
1590
|
+
# use the possibly incorrect counter cache column values and always get the results from the database,
|
|
1591
|
+
# use <tt>counter_cache: { active: false }</tt>.
|
|
1592
|
+
# If you also need to specify a custom column name, use <tt>counter_cache: { active: false, column: :my_custom_counter }</tt>.
|
|
1593
|
+
#
|
|
1609
1594
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
|
1610
1595
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
|
1611
|
-
# [
|
|
1596
|
+
# [+:polymorphic+]
|
|
1597
|
+
# Specify this association is a polymorphic association by passing +true+.
|
|
1598
|
+
# Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the
|
|
1599
|
+
# <tt>*_type</tt> polymorphic type column of the corresponding rows.
|
|
1600
|
+
# [+:validate+]
|
|
1612
1601
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
|
1613
1602
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
1614
|
-
# [
|
|
1603
|
+
# [+:autosave+]
|
|
1615
1604
|
# If true, always save the associated object or destroy it if marked for destruction, when
|
|
1616
1605
|
# saving the parent object.
|
|
1617
1606
|
# If false, never save or destroy the associated object.
|
|
@@ -1619,27 +1608,38 @@ module ActiveRecord
|
|
|
1619
1608
|
#
|
|
1620
1609
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for
|
|
1621
1610
|
# sets <tt>:autosave</tt> to <tt>true</tt>.
|
|
1622
|
-
# [
|
|
1623
|
-
# If true, the associated object will be touched (the updated_at/
|
|
1611
|
+
# [+:touch+]
|
|
1612
|
+
# If true, the associated object will be touched (the +updated_at+ / +updated_on+ attributes set to current time)
|
|
1624
1613
|
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
|
1625
|
-
# will be updated with the current time in addition to the updated_at/
|
|
1626
|
-
# Please note that
|
|
1627
|
-
# +after_commit
|
|
1628
|
-
# [
|
|
1614
|
+
# will be updated with the current time in addition to the +updated_at+ / +updated_on+ attribute.
|
|
1615
|
+
# Please note that no validation will be performed when touching, and only the +after_touch+,
|
|
1616
|
+
# +after_commit+, and +after_rollback+ callbacks will be executed.
|
|
1617
|
+
# [+:inverse_of+]
|
|
1629
1618
|
# Specifies the name of the #has_one or #has_many association on the associated
|
|
1630
1619
|
# object that is the inverse of this #belongs_to association.
|
|
1631
|
-
# See
|
|
1632
|
-
#
|
|
1620
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1621
|
+
# for more detail.
|
|
1622
|
+
# [+:optional+]
|
|
1633
1623
|
# When set to +true+, the association will not have its presence validated.
|
|
1634
|
-
# [
|
|
1624
|
+
# [+:required+]
|
|
1635
1625
|
# When set to +true+, the association will also have its presence validated.
|
|
1636
1626
|
# This will validate the association itself, not the id. You can use
|
|
1637
1627
|
# +:inverse_of+ to avoid an extra query during validation.
|
|
1638
1628
|
# NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If
|
|
1639
1629
|
# you don't want to have association presence validated, use <tt>optional: true</tt>.
|
|
1640
|
-
# [
|
|
1630
|
+
# [+:default+]
|
|
1641
1631
|
# Provide a callable (i.e. proc or lambda) to specify that the association should
|
|
1642
1632
|
# be initialized with a particular record before validation.
|
|
1633
|
+
# Please note that callable won't be executed if the record exists.
|
|
1634
|
+
# [+:strict_loading+]
|
|
1635
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
|
1636
|
+
# [+:ensuring_owner_was+]
|
|
1637
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
|
1638
|
+
# associated records to be deleted in a background job.
|
|
1639
|
+
# [+:query_constraints+]
|
|
1640
|
+
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1641
|
+
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1642
|
+
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1643
1643
|
#
|
|
1644
1644
|
# Option examples:
|
|
1645
1645
|
# belongs_to :firm, foreign_key: "client_of"
|
|
@@ -1654,6 +1654,8 @@ module ActiveRecord
|
|
|
1654
1654
|
# belongs_to :company, touch: :employees_last_updated_at
|
|
1655
1655
|
# belongs_to :user, optional: true
|
|
1656
1656
|
# belongs_to :account, default: -> { company.account }
|
|
1657
|
+
# belongs_to :account, strict_loading: true
|
|
1658
|
+
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
|
1657
1659
|
def belongs_to(name, scope = nil, **options)
|
|
1658
1660
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
|
1659
1661
|
Reflection.add_reflection self, name, reflection
|
|
@@ -1676,7 +1678,7 @@ module ActiveRecord
|
|
|
1676
1678
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
|
1677
1679
|
# join table with a migration such as this:
|
|
1678
1680
|
#
|
|
1679
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
|
1681
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[7.2]
|
|
1680
1682
|
# def change
|
|
1681
1683
|
# create_join_table :developers, :projects
|
|
1682
1684
|
# end
|
|
@@ -1691,71 +1693,80 @@ module ActiveRecord
|
|
|
1691
1693
|
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
|
1692
1694
|
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
|
1693
1695
|
#
|
|
1694
|
-
# [collection]
|
|
1696
|
+
# [<tt>collection</tt>]
|
|
1695
1697
|
# Returns a Relation of all the associated objects.
|
|
1696
1698
|
# An empty Relation is returned if none are found.
|
|
1697
|
-
# [collection<<(object, ...)]
|
|
1699
|
+
# [<tt>collection<<(object, ...)</tt>]
|
|
1698
1700
|
# Adds one or more objects to the collection by creating associations in the join table
|
|
1699
1701
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
|
1700
1702
|
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
|
1701
1703
|
# parent object, unless the parent object is a new record.
|
|
1702
|
-
# [collection.delete(object, ...)]
|
|
1704
|
+
# [<tt>collection.delete(object, ...)</tt>]
|
|
1703
1705
|
# Removes one or more objects from the collection by removing their associations from the join table.
|
|
1704
1706
|
# This does not destroy the objects.
|
|
1705
|
-
# [collection.destroy(object, ...)]
|
|
1707
|
+
# [<tt>collection.destroy(object, ...)</tt>]
|
|
1706
1708
|
# Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
|
|
1707
1709
|
# This does not destroy the objects.
|
|
1708
|
-
# [collection=objects]
|
|
1710
|
+
# [<tt>collection=objects</tt>]
|
|
1709
1711
|
# Replaces the collection's content by deleting and adding objects as appropriate.
|
|
1710
|
-
# [collection_singular_ids]
|
|
1712
|
+
# [<tt>collection_singular_ids</tt>]
|
|
1711
1713
|
# Returns an array of the associated objects' ids.
|
|
1712
|
-
# [collection_singular_ids=ids]
|
|
1714
|
+
# [<tt>collection_singular_ids=ids</tt>]
|
|
1713
1715
|
# Replace the collection by the objects identified by the primary keys in +ids+.
|
|
1714
|
-
# [collection.clear]
|
|
1716
|
+
# [<tt>collection.clear</tt>]
|
|
1715
1717
|
# Removes every object from the collection. This does not destroy the objects.
|
|
1716
|
-
# [collection.empty
|
|
1718
|
+
# [<tt>collection.empty?</tt>]
|
|
1717
1719
|
# Returns +true+ if there are no associated objects.
|
|
1718
|
-
# [collection.size]
|
|
1720
|
+
# [<tt>collection.size</tt>]
|
|
1719
1721
|
# Returns the number of associated objects.
|
|
1720
|
-
# [collection.find(id)]
|
|
1722
|
+
# [<tt>collection.find(id)</tt>]
|
|
1721
1723
|
# Finds an associated object responding to the +id+ and that
|
|
1722
1724
|
# meets the condition that it has to be associated with this object.
|
|
1723
1725
|
# Uses the same rules as ActiveRecord::FinderMethods#find.
|
|
1724
|
-
# [collection.exists?(...)]
|
|
1726
|
+
# [<tt>collection.exists?(...)</tt>]
|
|
1725
1727
|
# Checks whether an associated object with the given conditions exists.
|
|
1726
1728
|
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
|
|
1727
|
-
# [collection.build(attributes = {})]
|
|
1729
|
+
# [<tt>collection.build(attributes = {})</tt>]
|
|
1728
1730
|
# Returns a new object of the collection type that has been instantiated
|
|
1729
1731
|
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
|
|
1730
|
-
# [collection.create(attributes = {})]
|
|
1732
|
+
# [<tt>collection.create(attributes = {})</tt>]
|
|
1731
1733
|
# Returns a new object of the collection type that has been instantiated
|
|
1732
1734
|
# with +attributes+, linked to this object through the join table, and that has already been
|
|
1733
1735
|
# saved (if it passed the validation).
|
|
1734
|
-
# [collection.reload]
|
|
1736
|
+
# [<tt>collection.reload</tt>]
|
|
1735
1737
|
# Returns a Relation of all of the associated objects, forcing a database read.
|
|
1736
1738
|
# An empty Relation is returned if none are found.
|
|
1737
1739
|
#
|
|
1738
|
-
#
|
|
1739
|
-
#
|
|
1740
|
-
#
|
|
1741
|
-
#
|
|
1742
|
-
#
|
|
1743
|
-
#
|
|
1744
|
-
#
|
|
1745
|
-
#
|
|
1746
|
-
#
|
|
1747
|
-
#
|
|
1748
|
-
#
|
|
1749
|
-
#
|
|
1750
|
-
#
|
|
1751
|
-
#
|
|
1752
|
-
#
|
|
1753
|
-
#
|
|
1754
|
-
#
|
|
1755
|
-
#
|
|
1740
|
+
# ==== Example
|
|
1741
|
+
#
|
|
1742
|
+
# class Developer < ActiveRecord::Base
|
|
1743
|
+
# has_and_belongs_to_many :projects
|
|
1744
|
+
# end
|
|
1745
|
+
#
|
|
1746
|
+
# Declaring <tt>has_and_belongs_to_many :projects</tt> adds the following methods (and more):
|
|
1747
|
+
#
|
|
1748
|
+
# developer = Developer.find(11)
|
|
1749
|
+
# project = Project.find(9)
|
|
1750
|
+
#
|
|
1751
|
+
# developer.projects
|
|
1752
|
+
# developer.projects << project
|
|
1753
|
+
# developer.projects.delete(project)
|
|
1754
|
+
# developer.projects.destroy(project)
|
|
1755
|
+
# developer.projects = [project]
|
|
1756
|
+
# developer.project_ids
|
|
1757
|
+
# developer.project_ids = [9]
|
|
1758
|
+
# developer.projects.clear
|
|
1759
|
+
# developer.projects.empty?
|
|
1760
|
+
# developer.projects.size
|
|
1761
|
+
# developer.projects.find(9)
|
|
1762
|
+
# developer.projects.exists?(9)
|
|
1763
|
+
# developer.projects.build # similar to Project.new(developer_id: 11)
|
|
1764
|
+
# developer.projects.create # similar to Project.create(developer_id: 11)
|
|
1765
|
+
# developer.projects.reload
|
|
1766
|
+
#
|
|
1756
1767
|
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
|
1757
1768
|
#
|
|
1758
|
-
#
|
|
1769
|
+
# ==== Scopes
|
|
1759
1770
|
#
|
|
1760
1771
|
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
|
1761
1772
|
# lambda) to retrieve a specific set of records or customize the generated
|
|
@@ -1767,11 +1778,11 @@ module ActiveRecord
|
|
|
1767
1778
|
# where("default_category = ?", post.default_category)
|
|
1768
1779
|
# }
|
|
1769
1780
|
#
|
|
1770
|
-
#
|
|
1781
|
+
# ==== Extensions
|
|
1771
1782
|
#
|
|
1772
1783
|
# The +extension+ argument allows you to pass a block into a
|
|
1773
1784
|
# has_and_belongs_to_many association. This is useful for adding new
|
|
1774
|
-
# finders, creators and other factory-type methods to be used as part of
|
|
1785
|
+
# finders, creators, and other factory-type methods to be used as part of
|
|
1775
1786
|
# the association.
|
|
1776
1787
|
#
|
|
1777
1788
|
# Extension examples:
|
|
@@ -1782,33 +1793,33 @@ module ActiveRecord
|
|
|
1782
1793
|
# end
|
|
1783
1794
|
# end
|
|
1784
1795
|
#
|
|
1785
|
-
#
|
|
1796
|
+
# ==== Options
|
|
1786
1797
|
#
|
|
1787
|
-
# [
|
|
1798
|
+
# [+:class_name+]
|
|
1788
1799
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1789
1800
|
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
|
|
1790
1801
|
# Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
|
|
1791
|
-
# [
|
|
1802
|
+
# [+:join_table+]
|
|
1792
1803
|
# Specify the name of the join table if the default based on lexical order isn't what you want.
|
|
1793
1804
|
# <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method
|
|
1794
1805
|
# MUST be declared underneath any #has_and_belongs_to_many declaration in order to work.
|
|
1795
|
-
# [
|
|
1806
|
+
# [+:foreign_key+]
|
|
1796
1807
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1797
1808
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes
|
|
1798
1809
|
# a #has_and_belongs_to_many association to Project will use "person_id" as the
|
|
1799
1810
|
# default <tt>:foreign_key</tt>.
|
|
1800
1811
|
#
|
|
1801
|
-
#
|
|
1802
|
-
# a good idea to set the <tt>:inverse_of</tt> option.
|
|
1803
|
-
# [
|
|
1812
|
+
# Setting the <tt>:foreign_key</tt> option prevents automatic detection of the association's
|
|
1813
|
+
# inverse, so it is generally a good idea to set the <tt>:inverse_of</tt> option as well.
|
|
1814
|
+
# [+:association_foreign_key+]
|
|
1804
1815
|
# Specify the foreign key used for the association on the receiving side of the association.
|
|
1805
1816
|
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
|
|
1806
1817
|
# So if a Person class makes a #has_and_belongs_to_many association to Project,
|
|
1807
1818
|
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
|
|
1808
|
-
# [
|
|
1819
|
+
# [+:validate+]
|
|
1809
1820
|
# When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
|
|
1810
1821
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
1811
|
-
# [
|
|
1822
|
+
# [+:autosave+]
|
|
1812
1823
|
# If true, always save the associated objects or destroy them if marked for destruction, when
|
|
1813
1824
|
# saving the parent object.
|
|
1814
1825
|
# If false, never save or destroy the associated objects.
|
|
@@ -1816,6 +1827,8 @@ module ActiveRecord
|
|
|
1816
1827
|
#
|
|
1817
1828
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
|
1818
1829
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
1830
|
+
# [+:strict_loading+]
|
|
1831
|
+
# Enforces strict loading every time an associated record is loaded through this association.
|
|
1819
1832
|
#
|
|
1820
1833
|
# Option examples:
|
|
1821
1834
|
# has_and_belongs_to_many :projects
|
|
@@ -1823,6 +1836,7 @@ module ActiveRecord
|
|
|
1823
1836
|
# has_and_belongs_to_many :nations, class_name: "Country"
|
|
1824
1837
|
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
|
1825
1838
|
# has_and_belongs_to_many :categories, -> { readonly }
|
|
1839
|
+
# has_and_belongs_to_many :categories, strict_loading: true
|
|
1826
1840
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
|
1827
1841
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
|
1828
1842
|
|
|
@@ -1853,12 +1867,12 @@ module ActiveRecord
|
|
|
1853
1867
|
hm_options[:through] = middle_reflection.name
|
|
1854
1868
|
hm_options[:source] = join_model.right_reflection.name
|
|
1855
1869
|
|
|
1856
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
|
|
1870
|
+
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
|
1857
1871
|
hm_options[k] = options[k] if options.key? k
|
|
1858
1872
|
end
|
|
1859
1873
|
|
|
1860
|
-
has_many name, scope, hm_options, &extension
|
|
1861
|
-
_reflections[name
|
|
1874
|
+
has_many name, scope, **hm_options, &extension
|
|
1875
|
+
_reflections[name].parent_reflection = habtm_reflection
|
|
1862
1876
|
end
|
|
1863
1877
|
end
|
|
1864
1878
|
end
|