activerecord 4.2.9 → 6.1.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +964 -1382
- data/MIT-LICENSE +4 -2
- data/README.rdoc +15 -14
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +40 -15
- data/lib/active_record/associations/alias_tracker.rb +40 -43
- data/lib/active_record/associations/association.rb +162 -69
- data/lib/active_record/associations/association_scope.rb +105 -130
- data/lib/active_record/associations/belongs_to_association.rb +83 -65
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +57 -43
- data/lib/active_record/associations/builder/belongs_to.rb +74 -57
- data/lib/active_record/associations/builder/collection_association.rb +15 -37
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
- data/lib/active_record/associations/builder/has_many.rb +13 -5
- data/lib/active_record/associations/builder/has_one.rb +44 -6
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +148 -287
- data/lib/active_record/associations/collection_proxy.rb +252 -150
- data/lib/active_record/associations/foreign_association.rb +23 -1
- data/lib/active_record/associations/has_many_association.rb +56 -98
- data/lib/active_record/associations/has_many_through_association.rb +68 -89
- data/lib/active_record/associations/has_one_association.rb +73 -47
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/join_dependency.rb +174 -169
- data/lib/active_record/associations/preloader/association.rb +108 -115
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +97 -94
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +39 -19
- data/lib/active_record/associations.rb +1845 -1598
- data/lib/active_record/attribute_assignment.rb +59 -185
- data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
- data/lib/active_record/attribute_methods/dirty.rb +168 -148
- data/lib/active_record/attribute_methods/primary_key.rb +93 -83
- data/lib/active_record/attribute_methods/query.rb +8 -10
- data/lib/active_record/attribute_methods/read.rb +19 -79
- data/lib/active_record/attribute_methods/serialization.rb +49 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
- data/lib/active_record/attribute_methods/write.rb +24 -55
- data/lib/active_record/attribute_methods.rb +149 -154
- data/lib/active_record/attributes.rb +234 -78
- data/lib/active_record/autosave_association.rb +133 -60
- data/lib/active_record/base.rb +46 -46
- data/lib/active_record/callbacks.rb +234 -79
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
- data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
- data/lib/active_record/connection_adapters/column.rb +67 -40
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
- data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +314 -41
- data/lib/active_record/core.rb +458 -241
- data/lib/active_record/counter_cache.rb +70 -49
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +211 -92
- data/lib/active_record/errors.rb +224 -54
- data/lib/active_record/explain.rb +27 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +33 -14
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +275 -500
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +175 -110
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +121 -29
- data/lib/active_record/internal_metadata.rb +62 -0
- data/lib/active_record/legacy_yaml_adapter.rb +27 -5
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +98 -92
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +93 -31
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +185 -90
- data/lib/active_record/migration/compatibility.rb +295 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +673 -325
- data/lib/active_record/model_schema.rb +418 -113
- data/lib/active_record/nested_attributes.rb +263 -224
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +572 -136
- data/lib/active_record/query_cache.rb +29 -23
- data/lib/active_record/querying.rb +50 -31
- data/lib/active_record/railtie.rb +170 -51
- data/lib/active_record/railties/console_sandbox.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +523 -199
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +454 -291
- data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
- data/lib/active_record/relation/batches.rb +217 -59
- data/lib/active_record/relation/calculations.rb +324 -249
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +316 -242
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +95 -103
- data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +136 -122
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +757 -413
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -20
- data/lib/active_record/relation/where_clause.rb +239 -0
- data/lib/active_record/relation.rb +554 -343
- data/lib/active_record/result.rb +91 -47
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +134 -122
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +141 -92
- data/lib/active_record/schema_migration.rb +24 -23
- data/lib/active_record/scoping/default.rb +96 -83
- data/lib/active_record/scoping/named.rb +78 -36
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +48 -0
- data/lib/active_record/serialization.rb +8 -6
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +89 -36
- data/lib/active_record/store.rb +128 -43
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +81 -0
- data/lib/active_record/tasks/database_tasks.rb +364 -130
- data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
- data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +86 -43
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +182 -163
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +27 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +21 -16
- data/lib/active_record/type/type_map.rb +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +84 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +12 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +63 -56
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -29
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
- data/lib/rails/generators/active_record/migration.rb +35 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
- 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 +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +172 -65
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_decorators.rb +0 -66
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord::Associations
|
2
|
-
module ForeignAssociation
|
4
|
+
module ForeignAssociation # :nodoc:
|
3
5
|
def foreign_key_present?
|
4
6
|
if reflection.klass.primary_key
|
5
7
|
owner.attribute_present?(reflection.active_record_primary_key)
|
@@ -7,5 +9,25 @@ module ActiveRecord::Associations
|
|
7
9
|
false
|
8
10
|
end
|
9
11
|
end
|
12
|
+
|
13
|
+
def nullified_owner_attributes
|
14
|
+
Hash.new.tap do |attrs|
|
15
|
+
attrs[reflection.foreign_key] = nil
|
16
|
+
attrs[reflection.type] = nil if reflection.type.present?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
# Sets the owner attributes on the given record
|
22
|
+
def set_owner_attributes(record)
|
23
|
+
return if options[:through]
|
24
|
+
|
25
|
+
key = owner._read_attribute(reflection.join_foreign_key)
|
26
|
+
record._write_attribute(reflection.join_primary_key, key)
|
27
|
+
|
28
|
+
if reflection.type
|
29
|
+
record._write_attribute(reflection.type, owner.class.polymorphic_name)
|
30
|
+
end
|
31
|
+
end
|
10
32
|
end
|
11
33
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has Many Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has Many Association
|
4
6
|
# This is the proxy that handles a has many association.
|
5
7
|
#
|
6
8
|
# If the association has a <tt>:through</tt> option further specialization
|
@@ -15,43 +17,48 @@ module ActiveRecord
|
|
15
17
|
|
16
18
|
when :restrict_with_error
|
17
19
|
unless empty?
|
18
|
-
record =
|
19
|
-
owner.errors.add(:base, :
|
20
|
-
|
20
|
+
record = owner.class.human_attribute_name(reflection.name).downcase
|
21
|
+
owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
|
22
|
+
throw(:abort)
|
21
23
|
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
when :destroy
|
26
|
+
# No point in executing the counter update since we're going to destroy the parent anyway
|
27
|
+
load_target.each { |t| t.destroyed_by_association = reflection }
|
28
|
+
destroy_all
|
29
|
+
when :destroy_async
|
30
|
+
load_target.each do |t|
|
31
|
+
t.destroyed_by_association = reflection
|
30
32
|
end
|
31
|
-
end
|
32
|
-
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
unless target.empty?
|
35
|
+
association_class = target.first.class
|
36
|
+
primary_key_column = association_class.primary_key.to_sym
|
37
|
+
|
38
|
+
ids = target.collect do |assoc|
|
39
|
+
assoc.public_send(primary_key_column)
|
40
|
+
end
|
41
|
+
|
42
|
+
enqueue_destroy_association(
|
43
|
+
owner_model_name: owner.class.to_s,
|
44
|
+
owner_id: owner.id,
|
45
|
+
association_class: reflection.klass.to_s,
|
46
|
+
association_ids: ids,
|
47
|
+
association_primary_key_column: primary_key_column,
|
48
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
49
|
+
)
|
50
|
+
end
|
40
51
|
else
|
41
|
-
|
52
|
+
delete_all
|
42
53
|
end
|
43
54
|
end
|
44
55
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
else
|
49
|
-
super
|
50
|
-
end
|
56
|
+
def insert_record(record, validate = true, raise = false)
|
57
|
+
set_owner_attributes(record)
|
58
|
+
super
|
51
59
|
end
|
52
60
|
|
53
61
|
private
|
54
|
-
|
55
62
|
# Returns the number of records in this collection.
|
56
63
|
#
|
57
64
|
# If the association has a counter cache it gets that value. Otherwise
|
@@ -66,110 +73,53 @@ module ActiveRecord
|
|
66
73
|
# If the collection is empty the target is set to an empty array and
|
67
74
|
# the loaded flag is set to true as well.
|
68
75
|
def count_records
|
69
|
-
count = if has_cached_counter?
|
70
|
-
owner.
|
76
|
+
count = if reflection.has_cached_counter?
|
77
|
+
owner.read_attribute(reflection.counter_cache_column).to_i
|
71
78
|
else
|
72
|
-
scope.count
|
79
|
+
scope.count(:all)
|
73
80
|
end
|
74
81
|
|
75
82
|
# If there's nothing in the database and @target has no new records
|
76
83
|
# we are certain the current target is an empty array. This is a
|
77
84
|
# documented side-effect of the method that may avoid an extra SELECT.
|
78
|
-
|
85
|
+
loaded! if count == 0
|
79
86
|
|
80
87
|
[association_scope.limit_value, count].compact.min
|
81
88
|
end
|
82
89
|
|
83
|
-
|
84
|
-
# Returns whether a counter cache should be used for this association.
|
85
|
-
#
|
86
|
-
# The counter_cache option must be given on either the owner or inverse
|
87
|
-
# association, and the column must be present on the owner.
|
88
|
-
def has_cached_counter?(reflection = reflection())
|
89
|
-
if reflection.options[:counter_cache] || (inverse = inverse_which_updates_counter_cache(reflection)) && inverse.options[:counter_cache]
|
90
|
-
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def cached_counter_attribute_name(reflection = reflection())
|
95
|
-
if reflection.options[:counter_cache]
|
96
|
-
reflection.options[:counter_cache].to_s
|
97
|
-
else
|
98
|
-
"#{reflection.name}_count"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
90
|
def update_counter(difference, reflection = reflection())
|
103
|
-
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
def update_counter_in_database(difference, reflection = reflection())
|
108
|
-
if has_cached_counter?(reflection)
|
109
|
-
counter = cached_counter_attribute_name(reflection)
|
110
|
-
owner.class.update_counters(owner.id, counter => difference)
|
91
|
+
if reflection.has_cached_counter?
|
92
|
+
owner.increment!(reflection.counter_cache_column, difference)
|
111
93
|
end
|
112
94
|
end
|
113
95
|
|
114
96
|
def update_counter_in_memory(difference, reflection = reflection())
|
115
|
-
if counter_must_be_updated_by_has_many?
|
116
|
-
counter =
|
117
|
-
owner
|
118
|
-
owner.send(:
|
97
|
+
if reflection.counter_must_be_updated_by_has_many?
|
98
|
+
counter = reflection.counter_cache_column
|
99
|
+
owner.increment(counter, difference)
|
100
|
+
owner.send(:"clear_#{counter}_change")
|
119
101
|
end
|
120
102
|
end
|
121
103
|
|
122
|
-
# This shit is nasty. We need to avoid the following situation:
|
123
|
-
#
|
124
|
-
# * An associated record is deleted via record.destroy
|
125
|
-
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
126
|
-
# :counter_cache options which points back at our owner. So they update the
|
127
|
-
# counter cache.
|
128
|
-
# * In which case, we must make sure to *not* update the counter cache, or else
|
129
|
-
# it will be decremented twice.
|
130
|
-
#
|
131
|
-
# Hence this method.
|
132
|
-
def inverse_which_updates_counter_cache(reflection = reflection())
|
133
|
-
counter_name = cached_counter_attribute_name(reflection)
|
134
|
-
inverse_which_updates_counter_named(counter_name, reflection)
|
135
|
-
end
|
136
|
-
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
137
|
-
|
138
|
-
def inverse_which_updates_counter_named(counter_name, reflection)
|
139
|
-
reflection.klass._reflections.values.find { |inverse_reflection|
|
140
|
-
inverse_reflection.belongs_to? &&
|
141
|
-
inverse_reflection.counter_cache_column == counter_name
|
142
|
-
}
|
143
|
-
end
|
144
|
-
alias inverse_updates_counter_named? inverse_which_updates_counter_named
|
145
|
-
|
146
|
-
def inverse_updates_counter_in_memory?(reflection)
|
147
|
-
inverse = inverse_which_updates_counter_cache(reflection)
|
148
|
-
inverse && inverse == reflection.inverse_of
|
149
|
-
end
|
150
|
-
|
151
|
-
def counter_must_be_updated_by_has_many?(reflection)
|
152
|
-
!inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
|
153
|
-
end
|
154
|
-
|
155
104
|
def delete_count(method, scope)
|
156
105
|
if method == :delete_all
|
157
106
|
scope.delete_all
|
158
107
|
else
|
159
|
-
scope.update_all(
|
108
|
+
scope.update_all(nullified_owner_attributes)
|
160
109
|
end
|
161
110
|
end
|
162
111
|
|
163
112
|
def delete_or_nullify_all_records(method)
|
164
|
-
count = delete_count(method,
|
113
|
+
count = delete_count(method, scope)
|
165
114
|
update_counter(-count)
|
115
|
+
count
|
166
116
|
end
|
167
117
|
|
168
118
|
# Deletes the records according to the <tt>:dependent</tt> option.
|
169
119
|
def delete_records(records, method)
|
170
120
|
if method == :destroy
|
171
121
|
records.each(&:destroy!)
|
172
|
-
update_counter(-records.length) unless inverse_updates_counter_cache?
|
122
|
+
update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
|
173
123
|
else
|
174
124
|
scope = self.scope.where(reflection.klass.primary_key => records)
|
175
125
|
update_counter(-delete_count(method, scope))
|
@@ -194,6 +144,14 @@ module ActiveRecord
|
|
194
144
|
end
|
195
145
|
saved_successfully
|
196
146
|
end
|
147
|
+
|
148
|
+
def difference(a, b)
|
149
|
+
a - b
|
150
|
+
end
|
151
|
+
|
152
|
+
def intersection(a, b)
|
153
|
+
a & b
|
154
|
+
end
|
197
155
|
end
|
198
156
|
end
|
199
157
|
end
|
@@ -1,31 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
# = Active Record Has Many Through Association
|
5
4
|
module Associations
|
5
|
+
# = Active Record Has Many Through Association
|
6
6
|
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
|
7
7
|
include ThroughAssociation
|
8
8
|
|
9
9
|
def initialize(owner, reflection)
|
10
10
|
super
|
11
|
-
|
12
|
-
@through_records = {}
|
13
|
-
@through_association = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
# Returns the size of the collection by executing a SELECT COUNT(*) query
|
17
|
-
# if the collection hasn't been loaded, and by calling collection.size if
|
18
|
-
# it has. If the collection will likely have a size greater than zero,
|
19
|
-
# and if fetching the collection will be needed afterwards, one less
|
20
|
-
# SELECT query will be generated by using #length instead.
|
21
|
-
def size
|
22
|
-
if has_cached_counter?
|
23
|
-
owner._read_attribute cached_counter_attribute_name(reflection)
|
24
|
-
elsif loaded?
|
25
|
-
target.size
|
26
|
-
else
|
27
|
-
super
|
28
|
-
end
|
11
|
+
@through_records = {}.compare_by_identity
|
29
12
|
end
|
30
13
|
|
31
14
|
def concat(*records)
|
@@ -38,49 +21,31 @@ module ActiveRecord
|
|
38
21
|
super
|
39
22
|
end
|
40
23
|
|
41
|
-
def concat_records(records)
|
42
|
-
ensure_not_nested
|
43
|
-
|
44
|
-
records = super(records, true)
|
45
|
-
|
46
|
-
if owner.new_record? && records
|
47
|
-
records.flatten.each do |record|
|
48
|
-
build_through_record(record)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
records
|
53
|
-
end
|
54
|
-
|
55
24
|
def insert_record(record, validate = true, raise = false)
|
56
25
|
ensure_not_nested
|
57
26
|
|
58
|
-
if record.new_record?
|
59
|
-
|
60
|
-
record.save!(:validate => validate)
|
61
|
-
else
|
62
|
-
return unless record.save(:validate => validate)
|
63
|
-
end
|
27
|
+
if record.new_record? || record.has_changes_to_save?
|
28
|
+
return unless super
|
64
29
|
end
|
65
30
|
|
66
31
|
save_through_record(record)
|
67
|
-
if has_cached_counter? && !through_reflection_updates_counter_cache?
|
68
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
69
|
-
Automatic updating of counter caches on through associations has been
|
70
|
-
deprecated, and will be removed in Rails 5. Instead, please set the
|
71
|
-
appropriate `counter_cache` options on the `has_many` and `belongs_to`
|
72
|
-
for your associations to #{through_reflection.name}.
|
73
|
-
MSG
|
74
32
|
|
75
|
-
update_counter_in_database(1)
|
76
|
-
end
|
77
33
|
record
|
78
34
|
end
|
79
35
|
|
80
36
|
private
|
37
|
+
def concat_records(records)
|
38
|
+
ensure_not_nested
|
39
|
+
|
40
|
+
records = super(records, true)
|
81
41
|
|
82
|
-
|
83
|
-
|
42
|
+
if owner.new_record? && records
|
43
|
+
records.flatten.each do |record|
|
44
|
+
build_through_record(record)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
records
|
84
49
|
end
|
85
50
|
|
86
51
|
# The through record (built with build_record) is temporarily cached
|
@@ -89,40 +54,40 @@ module ActiveRecord
|
|
89
54
|
# However, after insert_record has been called, the cache is cleared in
|
90
55
|
# order to allow multiple instances of the same record in an association.
|
91
56
|
def build_through_record(record)
|
92
|
-
@through_records[record
|
57
|
+
@through_records[record] ||= begin
|
93
58
|
ensure_mutable
|
94
59
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
if options[:source_type]
|
99
|
-
through_record.send("#{source_reflection.foreign_type}=", options[:source_type])
|
100
|
-
end
|
60
|
+
attributes = through_scope_attributes
|
61
|
+
attributes[source_reflection.name] = record
|
62
|
+
attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
|
101
63
|
|
102
|
-
|
64
|
+
through_association.build(attributes)
|
103
65
|
end
|
104
66
|
end
|
105
67
|
|
106
|
-
|
107
|
-
[through_scope_attributes]
|
108
|
-
end
|
68
|
+
attr_reader :through_scope
|
109
69
|
|
110
70
|
def through_scope_attributes
|
71
|
+
scope = through_scope || self.scope
|
111
72
|
scope.where_values_hash(through_association.reflection.name.to_s).
|
112
73
|
except!(through_association.reflection.foreign_key,
|
113
74
|
through_association.reflection.klass.inheritance_column)
|
114
75
|
end
|
115
76
|
|
116
77
|
def save_through_record(record)
|
117
|
-
build_through_record(record)
|
78
|
+
association = build_through_record(record)
|
79
|
+
if association.changed?
|
80
|
+
association.save!
|
81
|
+
end
|
118
82
|
ensure
|
119
|
-
@through_records.delete(record
|
83
|
+
@through_records.delete(record)
|
120
84
|
end
|
121
85
|
|
122
86
|
def build_record(attributes)
|
123
87
|
ensure_not_nested
|
124
88
|
|
125
|
-
|
89
|
+
@through_scope = scope
|
90
|
+
record = super
|
126
91
|
|
127
92
|
inverse = source_reflection.inverse_of
|
128
93
|
if inverse
|
@@ -134,6 +99,13 @@ module ActiveRecord
|
|
134
99
|
end
|
135
100
|
|
136
101
|
record
|
102
|
+
ensure
|
103
|
+
@through_scope = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def remove_records(existing_records, records, method)
|
107
|
+
super
|
108
|
+
delete_through_records(records)
|
137
109
|
end
|
138
110
|
|
139
111
|
def target_reflection_has_associated_record?
|
@@ -143,7 +115,7 @@ module ActiveRecord
|
|
143
115
|
def update_through_counter?(method)
|
144
116
|
case method
|
145
117
|
when :destroy
|
146
|
-
!inverse_updates_counter_cache?
|
118
|
+
!through_reflection.inverse_updates_counter_cache?
|
147
119
|
when :nullify
|
148
120
|
false
|
149
121
|
else
|
@@ -160,23 +132,15 @@ module ActiveRecord
|
|
160
132
|
|
161
133
|
scope = through_association.scope
|
162
134
|
scope.where! construct_join_attributes(*records)
|
135
|
+
scope = scope.where(through_scope_attributes)
|
163
136
|
|
164
137
|
case method
|
165
138
|
when :destroy
|
166
139
|
if scope.klass.primary_key
|
167
|
-
count = scope.destroy_all.
|
140
|
+
count = scope.destroy_all.count(&:destroyed?)
|
168
141
|
else
|
169
|
-
scope.each
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
arel = scope.arel
|
174
|
-
|
175
|
-
stmt = Arel::DeleteManager.new arel.engine
|
176
|
-
stmt.from scope.klass.arel_table
|
177
|
-
stmt.wheres = arel.constraints
|
178
|
-
|
179
|
-
count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
|
142
|
+
scope.each(&:_run_destroy_callbacks)
|
143
|
+
count = scope.delete_all
|
180
144
|
end
|
181
145
|
when :nullify
|
182
146
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
@@ -196,6 +160,30 @@ module ActiveRecord
|
|
196
160
|
else
|
197
161
|
update_counter(-count)
|
198
162
|
end
|
163
|
+
|
164
|
+
count
|
165
|
+
end
|
166
|
+
|
167
|
+
def difference(a, b)
|
168
|
+
distribution = distribution(b)
|
169
|
+
|
170
|
+
a.reject { |record| mark_occurrence(distribution, record) }
|
171
|
+
end
|
172
|
+
|
173
|
+
def intersection(a, b)
|
174
|
+
distribution = distribution(b)
|
175
|
+
|
176
|
+
a.select { |record| mark_occurrence(distribution, record) }
|
177
|
+
end
|
178
|
+
|
179
|
+
def mark_occurrence(distribution, record)
|
180
|
+
distribution[record] > 0 && distribution[record] -= 1
|
181
|
+
end
|
182
|
+
|
183
|
+
def distribution(array)
|
184
|
+
array.each_with_object(Hash.new(0)) do |record, distribution|
|
185
|
+
distribution[record] += 1
|
186
|
+
end
|
199
187
|
end
|
200
188
|
|
201
189
|
def through_records_for(record)
|
@@ -220,28 +208,19 @@ module ActiveRecord
|
|
220
208
|
end
|
221
209
|
end
|
222
210
|
|
223
|
-
@through_records.delete(record
|
211
|
+
@through_records.delete(record)
|
224
212
|
end
|
225
213
|
end
|
226
214
|
|
227
215
|
def find_target
|
228
216
|
return [] unless target_reflection_has_associated_record?
|
229
|
-
|
217
|
+
super
|
230
218
|
end
|
231
219
|
|
232
220
|
# NOTE - not sure that we can actually cope with inverses here
|
233
221
|
def invertible_for?(record)
|
234
222
|
false
|
235
223
|
end
|
236
|
-
|
237
|
-
def has_cached_counter?(reflection = reflection())
|
238
|
-
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
239
|
-
end
|
240
|
-
|
241
|
-
def through_reflection_updates_counter_cache?
|
242
|
-
counter_name = cached_counter_attribute_name
|
243
|
-
inverse_updates_counter_named?(counter_name, through_reflection)
|
244
|
-
end
|
245
224
|
end
|
246
225
|
end
|
247
226
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Belongs To Has One Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Association
|
4
6
|
class HasOneAssociation < SingularAssociation #:nodoc:
|
5
7
|
include ForeignAssociation
|
6
8
|
|
@@ -11,9 +13,9 @@ module ActiveRecord
|
|
11
13
|
|
12
14
|
when :restrict_with_error
|
13
15
|
if load_target
|
14
|
-
record =
|
15
|
-
owner.errors.add(:base, :
|
16
|
-
|
16
|
+
record = owner.class.human_attribute_name(reflection.name).downcase
|
17
|
+
owner.errors.add(:base, :'restrict_dependent_destroy.has_one', record: record)
|
18
|
+
throw(:abort)
|
17
19
|
end
|
18
20
|
|
19
21
|
else
|
@@ -21,49 +23,61 @@ module ActiveRecord
|
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
26
|
+
def delete(method = options[:dependent])
|
27
|
+
if load_target
|
28
|
+
case method
|
29
|
+
when :delete
|
30
|
+
target.delete
|
31
|
+
when :destroy
|
32
|
+
target.destroyed_by_association = reflection
|
33
|
+
target.destroy
|
34
|
+
throw(:abort) unless target.destroyed?
|
35
|
+
when :destroy_async
|
36
|
+
primary_key_column = target.class.primary_key.to_sym
|
37
|
+
id = target.public_send(primary_key_column)
|
38
|
+
|
39
|
+
enqueue_destroy_association(
|
40
|
+
owner_model_name: owner.class.to_s,
|
41
|
+
owner_id: owner.id,
|
42
|
+
association_class: reflection.klass.to_s,
|
43
|
+
association_ids: [id],
|
44
|
+
association_primary_key_column: primary_key_column,
|
45
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
46
|
+
)
|
47
|
+
when :nullify
|
48
|
+
target.update_columns(nullified_owner_attributes) if target.persisted?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def replace(record, save = true)
|
55
|
+
raise_on_type_mismatch!(record) if record
|
27
56
|
|
28
|
-
|
57
|
+
return target unless load_target || record
|
29
58
|
|
30
|
-
|
31
|
-
|
32
|
-
|
59
|
+
assigning_another_record = target != record
|
60
|
+
if assigning_another_record || record.has_changes_to_save?
|
61
|
+
save &&= owner.persisted?
|
33
62
|
|
34
|
-
|
35
|
-
|
63
|
+
transaction_if(save) do
|
64
|
+
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
36
65
|
|
37
|
-
|
38
|
-
|
39
|
-
|
66
|
+
if record
|
67
|
+
set_owner_attributes(record)
|
68
|
+
set_inverse_instance(record)
|
40
69
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
70
|
+
if save && !record.save
|
71
|
+
nullify_owner_attributes(record)
|
72
|
+
set_owner_attributes(target) if target
|
73
|
+
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
74
|
+
end
|
45
75
|
end
|
46
76
|
end
|
47
77
|
end
|
48
|
-
end
|
49
78
|
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
def delete(method = options[:dependent])
|
54
|
-
if load_target
|
55
|
-
case method
|
56
|
-
when :delete
|
57
|
-
target.delete
|
58
|
-
when :destroy
|
59
|
-
target.destroy
|
60
|
-
when :nullify
|
61
|
-
target.update_columns(reflection.foreign_key => nil)
|
62
|
-
end
|
79
|
+
self.target = record
|
63
80
|
end
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
81
|
|
68
82
|
# The reason that the save param for replace is false, if for create (not just build),
|
69
83
|
# is because the setting of the foreign keys is actually handled by the scoping when
|
@@ -75,18 +89,22 @@ module ActiveRecord
|
|
75
89
|
|
76
90
|
def remove_target!(method)
|
77
91
|
case method
|
78
|
-
|
79
|
-
|
80
|
-
|
92
|
+
when :delete
|
93
|
+
target.delete
|
94
|
+
when :destroy
|
95
|
+
target.destroyed_by_association = reflection
|
96
|
+
if target.persisted?
|
81
97
|
target.destroy
|
82
|
-
|
83
|
-
|
98
|
+
end
|
99
|
+
else
|
100
|
+
nullify_owner_attributes(target)
|
101
|
+
remove_inverse_instance(target)
|
84
102
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
103
|
+
if target.persisted? && owner.persisted? && !target.save
|
104
|
+
set_owner_attributes(target)
|
105
|
+
raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " \
|
106
|
+
"The record failed to save after its foreign key was set to nil."
|
107
|
+
end
|
90
108
|
end
|
91
109
|
end
|
92
110
|
|
@@ -101,6 +119,14 @@ module ActiveRecord
|
|
101
119
|
yield
|
102
120
|
end
|
103
121
|
end
|
122
|
+
|
123
|
+
def _create_record(attributes, raise_error = false, &block)
|
124
|
+
unless owner.persisted?
|
125
|
+
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
126
|
+
end
|
127
|
+
|
128
|
+
super
|
129
|
+
end
|
104
130
|
end
|
105
131
|
end
|
106
132
|
end
|