activerecord 3.2.6 → 6.0.0
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 +7 -0
- data/CHANGELOG.md +611 -6417
- data/MIT-LICENSE +4 -2
- data/README.rdoc +44 -47
- data/examples/performance.rb +79 -71
- data/examples/simple.rb +6 -5
- data/lib/active_record/aggregations.rb +268 -238
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -42
- data/lib/active_record/associations/association.rb +173 -81
- data/lib/active_record/associations/association_scope.rb +124 -92
- data/lib/active_record/associations/belongs_to_association.rb +83 -38
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
- data/lib/active_record/associations/builder/association.rb +113 -32
- data/lib/active_record/associations/builder/belongs_to.rb +105 -60
- data/lib/active_record/associations/builder/collection_association.rb +53 -56
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
- data/lib/active_record/associations/builder/has_many.rb +11 -63
- data/lib/active_record/associations/builder/has_one.rb +47 -45
- data/lib/active_record/associations/builder/singular_association.rb +30 -18
- data/lib/active_record/associations/collection_association.rb +217 -295
- data/lib/active_record/associations/collection_proxy.rb +1074 -77
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +78 -50
- data/lib/active_record/associations/has_many_through_association.rb +99 -61
- data/lib/active_record/associations/has_one_association.rb +75 -30
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
- data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
- data/lib/active_record/associations/join_dependency.rb +208 -164
- data/lib/active_record/associations/preloader/association.rb +93 -87
- data/lib/active_record/associations/preloader/through_association.rb +87 -38
- data/lib/active_record/associations/preloader.rb +134 -110
- data/lib/active_record/associations/singular_association.rb +19 -24
- data/lib/active_record/associations/through_association.rb +61 -27
- data/lib/active_record/associations.rb +1766 -1505
- data/lib/active_record/attribute_assignment.rb +57 -193
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
- data/lib/active_record/attribute_methods/dirty.rb +187 -67
- data/lib/active_record/attribute_methods/primary_key.rb +100 -78
- data/lib/active_record/attribute_methods/query.rb +10 -8
- data/lib/active_record/attribute_methods/read.rb +29 -118
- data/lib/active_record/attribute_methods/serialization.rb +60 -72
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
- data/lib/active_record/attribute_methods/write.rb +36 -44
- data/lib/active_record/attribute_methods.rb +306 -161
- data/lib/active_record/attributes.rb +279 -0
- data/lib/active_record/autosave_association.rb +324 -238
- data/lib/active_record/base.rb +114 -507
- data/lib/active_record/callbacks.rb +147 -83
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +32 -23
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
- data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
- data/lib/active_record/connection_adapters/column.rb +58 -233
- data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
- data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -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 +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +267 -0
- data/lib/active_record/core.rb +599 -0
- data/lib/active_record/counter_cache.rb +177 -103
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +107 -64
- data/lib/active_record/enum.rb +274 -0
- data/lib/active_record/errors.rb +254 -61
- data/lib/active_record/explain.rb +35 -70
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +18 -8
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +291 -475
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +219 -100
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +175 -17
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +106 -92
- data/lib/active_record/locking/pessimistic.rb +23 -11
- data/lib/active_record/log_subscriber.rb +80 -30
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +235 -56
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/migration.rb +917 -301
- data/lib/active_record/model_schema.rb +351 -175
- data/lib/active_record/nested_attributes.rb +366 -235
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +761 -166
- data/lib/active_record/query_cache.rb +22 -44
- data/lib/active_record/querying.rb +55 -31
- data/lib/active_record/railtie.rb +185 -47
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -4
- data/lib/active_record/railties/controller_runtime.rb +35 -33
- data/lib/active_record/railties/databases.rake +366 -463
- data/lib/active_record/readonly_attributes.rb +4 -6
- data/lib/active_record/reflection.rb +736 -228
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +252 -52
- data/lib/active_record/relation/calculations.rb +340 -270
- data/lib/active_record/relation/delegation.rb +117 -36
- data/lib/active_record/relation/finder_methods.rb +439 -286
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +184 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -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 +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder.rb +131 -39
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +1163 -221
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +49 -120
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/relation.rb +671 -349
- data/lib/active_record/result.rb +149 -15
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +153 -133
- data/lib/active_record/schema.rb +22 -19
- data/lib/active_record/schema_dumper.rb +178 -112
- data/lib/active_record/schema_migration.rb +60 -0
- data/lib/active_record/scoping/default.rb +107 -98
- data/lib/active_record/scoping/named.rb +130 -115
- data/lib/active_record/scoping.rb +77 -123
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +10 -6
- data/lib/active_record/statement_cache.rb +148 -0
- data/lib/active_record/store.rb +256 -16
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +506 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +93 -39
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +260 -129
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- 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 +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +78 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -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 +35 -18
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +123 -77
- data/lib/active_record/validations.rb +54 -43
- data/lib/active_record/version.rb +7 -7
- data/lib/active_record.rb +97 -49
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -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 +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -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 +18 -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 +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -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 +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -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 +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -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 +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -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 +59 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/migration.rb +41 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
- 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} +1 -1
- data/lib/rails/generators/active_record.rb +10 -16
- metadata +285 -149
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- 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_and_belongs_to_many.rb +0 -60
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
- 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_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -358
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord::Associations
|
4
|
+
module ForeignAssociation # :nodoc:
|
5
|
+
def foreign_key_present?
|
6
|
+
if reflection.klass.primary_key
|
7
|
+
owner.attribute_present?(reflection.active_record_primary_key)
|
8
|
+
else
|
9
|
+
false
|
10
|
+
end
|
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
|
+
end
|
20
|
+
end
|
@@ -1,22 +1,41 @@
|
|
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
|
7
9
|
# is provided by its child HasManyThroughAssociation.
|
8
10
|
class HasManyAssociation < CollectionAssociation #:nodoc:
|
11
|
+
include ForeignAssociation
|
9
12
|
|
10
|
-
def
|
11
|
-
|
13
|
+
def handle_dependency
|
14
|
+
case options[:dependent]
|
15
|
+
when :restrict_with_exception
|
16
|
+
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
|
12
17
|
|
13
|
-
|
14
|
-
|
18
|
+
when :restrict_with_error
|
19
|
+
unless empty?
|
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)
|
23
|
+
end
|
24
|
+
|
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
|
15
29
|
else
|
16
|
-
|
30
|
+
delete_all
|
17
31
|
end
|
18
32
|
end
|
19
33
|
|
34
|
+
def insert_record(record, validate = true, raise = false)
|
35
|
+
set_owner_attributes(record)
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
20
39
|
private
|
21
40
|
|
22
41
|
# Returns the number of records in this collection.
|
@@ -33,75 +52,84 @@ module ActiveRecord
|
|
33
52
|
# If the collection is empty the target is set to an empty array and
|
34
53
|
# the loaded flag is set to true as well.
|
35
54
|
def count_records
|
36
|
-
count = if has_cached_counter?
|
37
|
-
owner.
|
38
|
-
elsif options[:counter_sql] || options[:finder_sql]
|
39
|
-
reflection.klass.count_by_sql(custom_counter_sql)
|
55
|
+
count = if reflection.has_cached_counter?
|
56
|
+
owner._read_attribute(reflection.counter_cache_column).to_i
|
40
57
|
else
|
41
|
-
|
58
|
+
scope.count(:all)
|
42
59
|
end
|
43
60
|
|
44
61
|
# If there's nothing in the database and @target has no new records
|
45
62
|
# we are certain the current target is an empty array. This is a
|
46
63
|
# documented side-effect of the method that may avoid an extra SELECT.
|
47
|
-
|
64
|
+
loaded! if count == 0
|
48
65
|
|
49
|
-
[
|
66
|
+
[association_scope.limit_value, count].compact.min
|
50
67
|
end
|
51
68
|
|
52
|
-
def
|
53
|
-
|
69
|
+
def update_counter(difference, reflection = reflection())
|
70
|
+
if reflection.has_cached_counter?
|
71
|
+
owner.increment!(reflection.counter_cache_column, difference)
|
72
|
+
end
|
54
73
|
end
|
55
74
|
|
56
|
-
def
|
57
|
-
|
75
|
+
def update_counter_in_memory(difference, reflection = reflection())
|
76
|
+
if reflection.counter_must_be_updated_by_has_many?
|
77
|
+
counter = reflection.counter_cache_column
|
78
|
+
owner.increment(counter, difference)
|
79
|
+
owner.send(:clear_attribute_change, counter) # eww
|
80
|
+
end
|
58
81
|
end
|
59
82
|
|
60
|
-
def
|
61
|
-
if
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
owner.changed_attributes.delete(counter) # eww
|
83
|
+
def delete_count(method, scope)
|
84
|
+
if method == :delete_all
|
85
|
+
scope.delete_all
|
86
|
+
else
|
87
|
+
scope.update_all(nullified_owner_attributes)
|
66
88
|
end
|
67
89
|
end
|
68
90
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# :counter_cache options which points back at our owner. So they update the
|
74
|
-
# counter cache.
|
75
|
-
# * In which case, we must make sure to *not* update the counter cache, or else
|
76
|
-
# it will be decremented twice.
|
77
|
-
#
|
78
|
-
# Hence this method.
|
79
|
-
def inverse_updates_counter_cache?(reflection = reflection)
|
80
|
-
counter_name = cached_counter_attribute_name(reflection)
|
81
|
-
reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
|
82
|
-
inverse_reflection.counter_cache_column == counter_name
|
83
|
-
}
|
91
|
+
def delete_or_nullify_all_records(method)
|
92
|
+
count = delete_count(method, scope)
|
93
|
+
update_counter(-count)
|
94
|
+
count
|
84
95
|
end
|
85
96
|
|
86
97
|
# Deletes the records according to the <tt>:dependent</tt> option.
|
87
98
|
def delete_records(records, method)
|
88
99
|
if method == :destroy
|
89
|
-
records.each
|
90
|
-
update_counter(-records.length) unless inverse_updates_counter_cache?
|
100
|
+
records.each(&:destroy!)
|
101
|
+
update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
|
102
|
+
else
|
103
|
+
scope = self.scope.where(reflection.klass.primary_key => records)
|
104
|
+
update_counter(-delete_count(method, scope))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def concat_records(records, *)
|
109
|
+
update_counter_if_success(super, records.length)
|
110
|
+
end
|
111
|
+
|
112
|
+
def _create_record(attributes, *)
|
113
|
+
if attributes.is_a?(Array)
|
114
|
+
super
|
91
115
|
else
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
116
|
+
update_counter_if_success(super, 1)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def update_counter_if_success(saved_successfully, difference)
|
121
|
+
if saved_successfully
|
122
|
+
update_counter_in_memory(difference)
|
100
123
|
end
|
124
|
+
saved_successfully
|
125
|
+
end
|
126
|
+
|
127
|
+
def difference(a, b)
|
128
|
+
a - b
|
101
129
|
end
|
102
130
|
|
103
|
-
def
|
104
|
-
|
131
|
+
def intersection(a, b)
|
132
|
+
a & b
|
105
133
|
end
|
106
134
|
end
|
107
135
|
end
|
@@ -1,37 +1,20 @@
|
|
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 if the collection hasn't been
|
17
|
-
# loaded and calling collection.size if it has. If it's more likely than not that the collection does
|
18
|
-
# have a size larger than zero, and you need to fetch that collection afterwards, it'll take one fewer
|
19
|
-
# SELECT query if you use #length.
|
20
|
-
def size
|
21
|
-
if has_cached_counter?
|
22
|
-
owner.send(:read_attribute, cached_counter_attribute_name)
|
23
|
-
elsif loaded?
|
24
|
-
target.size
|
25
|
-
else
|
26
|
-
count
|
27
|
-
end
|
11
|
+
@through_records = {}
|
28
12
|
end
|
29
13
|
|
30
14
|
def concat(*records)
|
31
15
|
unless owner.new_record?
|
32
16
|
records.flatten.each do |record|
|
33
|
-
raise_on_type_mismatch(record)
|
34
|
-
record.save! if record.new_record?
|
17
|
+
raise_on_type_mismatch!(record)
|
35
18
|
end
|
36
19
|
end
|
37
20
|
|
@@ -41,62 +24,72 @@ module ActiveRecord
|
|
41
24
|
def insert_record(record, validate = true, raise = false)
|
42
25
|
ensure_not_nested
|
43
26
|
|
44
|
-
if record.new_record?
|
45
|
-
|
46
|
-
record.save!(:validate => validate)
|
47
|
-
else
|
48
|
-
return unless record.save(:validate => validate)
|
49
|
-
end
|
27
|
+
if record.new_record? || record.has_changes_to_save?
|
28
|
+
return unless super
|
50
29
|
end
|
51
30
|
|
52
31
|
save_through_record(record)
|
53
|
-
|
32
|
+
|
54
33
|
record
|
55
34
|
end
|
56
35
|
|
57
|
-
# ActiveRecord::Relation#delete_all needs to support joins before we can use a
|
58
|
-
# SQL-only implementation.
|
59
|
-
alias delete_all_on_destroy delete_all
|
60
|
-
|
61
36
|
private
|
37
|
+
def concat_records(records)
|
38
|
+
ensure_not_nested
|
39
|
+
|
40
|
+
records = super(records, true)
|
62
41
|
|
63
|
-
|
64
|
-
|
42
|
+
if owner.new_record? && records
|
43
|
+
records.flatten.each do |record|
|
44
|
+
build_through_record(record)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
records
|
65
49
|
end
|
66
50
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# want to use the exact same object.
|
51
|
+
# The through record (built with build_record) is temporarily cached
|
52
|
+
# so that it may be reused if insert_record is subsequently called.
|
70
53
|
#
|
71
|
-
# However, after insert_record has been called,
|
72
|
-
#
|
73
|
-
# association
|
54
|
+
# However, after insert_record has been called, the cache is cleared in
|
55
|
+
# order to allow multiple instances of the same record in an association.
|
74
56
|
def build_through_record(record)
|
75
57
|
@through_records[record.object_id] ||= begin
|
76
58
|
ensure_mutable
|
77
59
|
|
78
|
-
|
79
|
-
|
80
|
-
|
60
|
+
attributes = through_scope_attributes
|
61
|
+
attributes[source_reflection.name] = record
|
62
|
+
attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
|
63
|
+
|
64
|
+
through_association.build(attributes)
|
81
65
|
end
|
82
66
|
end
|
83
67
|
|
68
|
+
def through_scope_attributes
|
69
|
+
scope.where_values_hash(through_association.reflection.name.to_s).
|
70
|
+
except!(through_association.reflection.foreign_key,
|
71
|
+
through_association.reflection.klass.inheritance_column)
|
72
|
+
end
|
73
|
+
|
84
74
|
def save_through_record(record)
|
85
|
-
build_through_record(record)
|
75
|
+
association = build_through_record(record)
|
76
|
+
if association.changed?
|
77
|
+
association.save!
|
78
|
+
end
|
86
79
|
ensure
|
87
80
|
@through_records.delete(record.object_id)
|
88
81
|
end
|
89
82
|
|
90
|
-
def build_record(attributes
|
83
|
+
def build_record(attributes)
|
91
84
|
ensure_not_nested
|
92
85
|
|
93
|
-
record = super
|
86
|
+
record = super
|
94
87
|
|
95
88
|
inverse = source_reflection.inverse_of
|
96
89
|
if inverse
|
97
|
-
if inverse.
|
90
|
+
if inverse.collection?
|
98
91
|
record.send(inverse.name) << build_through_record(record)
|
99
|
-
elsif inverse.
|
92
|
+
elsif inverse.has_one?
|
100
93
|
record.send("#{inverse.name}=", build_through_record(record))
|
101
94
|
end
|
102
95
|
end
|
@@ -104,18 +97,19 @@ module ActiveRecord
|
|
104
97
|
record
|
105
98
|
end
|
106
99
|
|
100
|
+
def remove_records(existing_records, records, method)
|
101
|
+
super
|
102
|
+
delete_through_records(records)
|
103
|
+
end
|
104
|
+
|
107
105
|
def target_reflection_has_associated_record?
|
108
|
-
|
109
|
-
false
|
110
|
-
else
|
111
|
-
true
|
112
|
-
end
|
106
|
+
!(through_reflection.belongs_to? && owner[through_reflection.foreign_key].blank?)
|
113
107
|
end
|
114
108
|
|
115
109
|
def update_through_counter?(method)
|
116
110
|
case method
|
117
111
|
when :destroy
|
118
|
-
!inverse_updates_counter_cache?
|
112
|
+
!through_reflection.inverse_updates_counter_cache?
|
119
113
|
when :nullify
|
120
114
|
false
|
121
115
|
else
|
@@ -123,14 +117,25 @@ module ActiveRecord
|
|
123
117
|
end
|
124
118
|
end
|
125
119
|
|
120
|
+
def delete_or_nullify_all_records(method)
|
121
|
+
delete_records(load_target, method)
|
122
|
+
end
|
123
|
+
|
126
124
|
def delete_records(records, method)
|
127
125
|
ensure_not_nested
|
128
126
|
|
129
|
-
scope = through_association.
|
127
|
+
scope = through_association.scope
|
128
|
+
scope.where! construct_join_attributes(*records)
|
129
|
+
scope = scope.where(through_scope_attributes)
|
130
130
|
|
131
131
|
case method
|
132
132
|
when :destroy
|
133
|
-
|
133
|
+
if scope.klass.primary_key
|
134
|
+
count = scope.destroy_all.count(&:destroyed?)
|
135
|
+
else
|
136
|
+
scope.each(&:_run_destroy_callbacks)
|
137
|
+
count = scope.delete_all
|
138
|
+
end
|
134
139
|
when :nullify
|
135
140
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
136
141
|
else
|
@@ -139,24 +144,57 @@ module ActiveRecord
|
|
139
144
|
|
140
145
|
delete_through_records(records)
|
141
146
|
|
142
|
-
if
|
147
|
+
if source_reflection.options[:counter_cache] && method != :destroy
|
148
|
+
counter = source_reflection.counter_cache_column
|
149
|
+
klass.decrement_counter counter, records.map(&:id)
|
150
|
+
end
|
151
|
+
|
152
|
+
if through_reflection.collection? && update_through_counter?(method)
|
143
153
|
update_counter(-count, through_reflection)
|
154
|
+
else
|
155
|
+
update_counter(-count)
|
144
156
|
end
|
145
157
|
|
146
|
-
|
158
|
+
count
|
159
|
+
end
|
160
|
+
|
161
|
+
def difference(a, b)
|
162
|
+
distribution = distribution(b)
|
163
|
+
|
164
|
+
a.reject { |record| mark_occurrence(distribution, record) }
|
165
|
+
end
|
166
|
+
|
167
|
+
def intersection(a, b)
|
168
|
+
distribution = distribution(b)
|
169
|
+
|
170
|
+
a.select { |record| mark_occurrence(distribution, record) }
|
171
|
+
end
|
172
|
+
|
173
|
+
def mark_occurrence(distribution, record)
|
174
|
+
distribution[record] > 0 && distribution[record] -= 1
|
175
|
+
end
|
176
|
+
|
177
|
+
def distribution(array)
|
178
|
+
array.each_with_object(Hash.new(0)) do |record, distribution|
|
179
|
+
distribution[record] += 1
|
180
|
+
end
|
147
181
|
end
|
148
182
|
|
149
183
|
def through_records_for(record)
|
150
184
|
attributes = construct_join_attributes(record)
|
151
185
|
candidates = Array.wrap(through_association.target)
|
152
|
-
candidates.find_all
|
186
|
+
candidates.find_all do |c|
|
187
|
+
attributes.all? do |key, value|
|
188
|
+
c.public_send(key) == value
|
189
|
+
end
|
190
|
+
end
|
153
191
|
end
|
154
192
|
|
155
193
|
def delete_through_records(records)
|
156
194
|
records.each do |record|
|
157
195
|
through_records = through_records_for(record)
|
158
196
|
|
159
|
-
if through_reflection.
|
197
|
+
if through_reflection.collection?
|
160
198
|
through_records.each { |r| through_association.target.delete(r) }
|
161
199
|
else
|
162
200
|
if through_records.include?(through_association.target)
|
@@ -170,7 +208,7 @@ module ActiveRecord
|
|
170
208
|
|
171
209
|
def find_target
|
172
210
|
return [] unless target_reflection_has_associated_record?
|
173
|
-
|
211
|
+
super
|
174
212
|
end
|
175
213
|
|
176
214
|
# NOTE - not sure that we can actually cope with inverses here
|
@@ -1,47 +1,71 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
# = Active Record Belongs To Has One Association
|
5
4
|
module Associations
|
5
|
+
# = Active Record Has One Association
|
6
6
|
class HasOneAssociation < SingularAssociation #:nodoc:
|
7
|
-
|
8
|
-
raise_on_type_mismatch(record) if record
|
9
|
-
load_target
|
7
|
+
include ForeignAssociation
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
if record
|
17
|
-
set_owner_attributes(record)
|
18
|
-
set_inverse_instance(record)
|
9
|
+
def handle_dependency
|
10
|
+
case options[:dependent]
|
11
|
+
when :restrict_with_exception
|
12
|
+
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) if load_target
|
19
13
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
when :restrict_with_error
|
15
|
+
if load_target
|
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)
|
25
19
|
end
|
26
|
-
end
|
27
20
|
|
28
|
-
|
21
|
+
else
|
22
|
+
delete
|
23
|
+
end
|
29
24
|
end
|
30
25
|
|
31
26
|
def delete(method = options[:dependent])
|
32
27
|
if load_target
|
33
28
|
case method
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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 :nullify
|
36
|
+
target.update_columns(nullified_owner_attributes) if target.persisted?
|
40
37
|
end
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
44
41
|
private
|
42
|
+
def replace(record, save = true)
|
43
|
+
raise_on_type_mismatch!(record) if record
|
44
|
+
|
45
|
+
return target unless load_target || record
|
46
|
+
|
47
|
+
assigning_another_record = target != record
|
48
|
+
if assigning_another_record || record.has_changes_to_save?
|
49
|
+
save &&= owner.persisted?
|
50
|
+
|
51
|
+
transaction_if(save) do
|
52
|
+
remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
|
53
|
+
|
54
|
+
if record
|
55
|
+
set_owner_attributes(record)
|
56
|
+
set_inverse_instance(record)
|
57
|
+
|
58
|
+
if save && !record.save
|
59
|
+
nullify_owner_attributes(record)
|
60
|
+
set_owner_attributes(target) if target
|
61
|
+
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
self.target = record
|
68
|
+
end
|
45
69
|
|
46
70
|
# The reason that the save param for replace is false, if for create (not just build),
|
47
71
|
# is because the setting of the foreign keys is actually handled by the scoping when
|
@@ -52,15 +76,20 @@ module ActiveRecord
|
|
52
76
|
end
|
53
77
|
|
54
78
|
def remove_target!(method)
|
55
|
-
|
56
|
-
|
79
|
+
case method
|
80
|
+
when :delete
|
81
|
+
target.delete
|
82
|
+
when :destroy
|
83
|
+
target.destroyed_by_association = reflection
|
84
|
+
target.destroy
|
57
85
|
else
|
58
86
|
nullify_owner_attributes(target)
|
87
|
+
remove_inverse_instance(target)
|
59
88
|
|
60
89
|
if target.persisted? && owner.persisted? && !target.save
|
61
90
|
set_owner_attributes(target)
|
62
|
-
raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. "
|
63
|
-
"The record failed to save
|
91
|
+
raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " \
|
92
|
+
"The record failed to save after its foreign key was set to nil."
|
64
93
|
end
|
65
94
|
end
|
66
95
|
end
|
@@ -68,6 +97,22 @@ module ActiveRecord
|
|
68
97
|
def nullify_owner_attributes(record)
|
69
98
|
record[reflection.foreign_key] = nil
|
70
99
|
end
|
100
|
+
|
101
|
+
def transaction_if(value)
|
102
|
+
if value
|
103
|
+
reflection.klass.transaction { yield }
|
104
|
+
else
|
105
|
+
yield
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def _create_record(attributes, raise_error = false, &block)
|
110
|
+
unless owner.persisted?
|
111
|
+
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
112
|
+
end
|
113
|
+
|
114
|
+
super
|
115
|
+
end
|
71
116
|
end
|
72
117
|
end
|
73
118
|
end
|
@@ -1,30 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has One Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Through Association
|
4
6
|
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
|
5
7
|
include ThroughAssociation
|
6
8
|
|
7
|
-
def replace(record)
|
8
|
-
create_through_record(record)
|
9
|
-
self.target = record
|
10
|
-
end
|
11
|
-
|
12
9
|
private
|
10
|
+
def replace(record, save = true)
|
11
|
+
create_through_record(record, save)
|
12
|
+
self.target = record
|
13
|
+
end
|
13
14
|
|
14
|
-
def create_through_record(record)
|
15
|
+
def create_through_record(record, save)
|
15
16
|
ensure_not_nested
|
16
17
|
|
17
|
-
through_proxy =
|
18
|
-
through_record = through_proxy.
|
18
|
+
through_proxy = through_association
|
19
|
+
through_record = through_proxy.load_target
|
19
20
|
|
20
21
|
if through_record && !record
|
21
22
|
through_record.destroy
|
22
23
|
elsif record
|
23
24
|
attributes = construct_join_attributes(record)
|
24
25
|
|
26
|
+
if through_record && through_record.destroyed?
|
27
|
+
through_record = through_proxy.tap(&:reload).target
|
28
|
+
end
|
29
|
+
|
25
30
|
if through_record
|
26
|
-
through_record.
|
27
|
-
|
31
|
+
if through_record.new_record?
|
32
|
+
through_record.assign_attributes(attributes)
|
33
|
+
else
|
34
|
+
through_record.update(attributes)
|
35
|
+
end
|
36
|
+
elsif owner.new_record? || !save
|
28
37
|
through_proxy.build(attributes)
|
29
38
|
else
|
30
39
|
through_proxy.create(attributes)
|