activerecord 5.0.7.2 → 6.0.6.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 +4 -4
- data/CHANGELOG.md +844 -1944
- data/MIT-LICENSE +3 -1
- data/README.rdoc +9 -7
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +18 -14
- data/lib/active_record/associations/alias_tracker.rb +24 -34
- data/lib/active_record/associations/association.rb +113 -55
- data/lib/active_record/associations/association_scope.rb +102 -96
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +93 -254
- data/lib/active_record/associations/collection_proxy.rb +159 -122
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -30
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -85
- 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 +152 -177
- data/lib/active_record/associations/preloader/association.rb +101 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/preloader.rb +94 -103
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -61
- data/lib/active_record/attribute_decorators.rb +38 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +85 -92
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +20 -49
- data/lib/active_record/attribute_methods/serialization.rb +29 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
- data/lib/active_record/attribute_methods/write.rb +34 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -25
- data/lib/active_record/autosave_association.rb +58 -39
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +64 -35
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +558 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +128 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +233 -147
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
- data/lib/active_record/connection_adapters/abstract_adapter.rb +373 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -562
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +12 -2
- 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 +19 -18
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -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/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- 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 +261 -267
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +143 -40
- data/lib/active_record/core.rb +207 -160
- data/lib/active_record/counter_cache.rb +60 -28
- 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 +78 -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 +87 -87
- data/lib/active_record/enum.rb +67 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -4
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- 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 +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +194 -504
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +150 -99
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +16 -19
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +85 -86
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +134 -100
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +369 -302
- data/lib/active_record/model_schema.rb +160 -127
- data/lib/active_record/nested_attributes.rb +213 -202
- data/lib/active_record/no_touching.rb +12 -3
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +446 -77
- data/lib/active_record/query_cache.rb +13 -12
- data/lib/active_record/querying.rb +37 -24
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +312 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +214 -254
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +98 -52
- data/lib/active_record/relation/calculations.rb +212 -173
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +207 -247
- data/lib/active_record/relation/from_clause.rb +6 -8
- data/lib/active_record/relation/merger.rb +82 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +83 -105
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +488 -332
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -96
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +443 -318
- data/lib/active_record/result.rb +69 -40
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +16 -6
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +51 -26
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +39 -18
- data/lib/active_record/tasks/database_tasks.rb +271 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
- data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +70 -36
- data/lib/active_record/touch_later.rb +8 -6
- data/lib/active_record/transactions.rb +141 -157
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -48
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +16 -9
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +12 -1
- data/lib/active_record/type/type_map.rb +14 -17
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type.rb +23 -18
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -2
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -5
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +37 -22
- 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 +256 -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 +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +138 -52
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- 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 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
- /data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,6 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/except"
|
4
|
+
require "active_support/core_ext/module/redefine_method"
|
5
|
+
require "active_support/core_ext/object/try"
|
6
|
+
require "active_support/core_ext/hash/indifferent_access"
|
4
7
|
|
5
8
|
module ActiveRecord
|
6
9
|
module NestedAttributes #:nodoc:
|
@@ -10,8 +13,7 @@ module ActiveRecord
|
|
10
13
|
extend ActiveSupport::Concern
|
11
14
|
|
12
15
|
included do
|
13
|
-
class_attribute :nested_attributes_options, instance_writer: false
|
14
|
-
self.nested_attributes_options = {}
|
16
|
+
class_attribute :nested_attributes_options, instance_writer: false, default: {}
|
15
17
|
end
|
16
18
|
|
17
19
|
# = Active Record Nested Attributes
|
@@ -61,6 +63,18 @@ module ActiveRecord
|
|
61
63
|
# member.update params[:member]
|
62
64
|
# member.avatar.icon # => 'sad'
|
63
65
|
#
|
66
|
+
# If you want to update the current avatar without providing the id, you must add <tt>:update_only</tt> option.
|
67
|
+
#
|
68
|
+
# class Member < ActiveRecord::Base
|
69
|
+
# has_one :avatar
|
70
|
+
# accepts_nested_attributes_for :avatar, update_only: true
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# params = { member: { avatar_attributes: { icon: 'sad' } } }
|
74
|
+
# member.update params[:member]
|
75
|
+
# member.avatar.id # => 2
|
76
|
+
# member.avatar.icon # => 'sad'
|
77
|
+
#
|
64
78
|
# By default you will only be able to set and update attributes on the
|
65
79
|
# associated model. If you want to destroy the associated model through the
|
66
80
|
# attributes hash, you have to enable it first using the
|
@@ -267,7 +281,7 @@ module ActiveRecord
|
|
267
281
|
# member.avatar_attributes = {icon: 'sad'}
|
268
282
|
# member.avatar.width # => 200
|
269
283
|
module ClassMethods
|
270
|
-
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key ==
|
284
|
+
REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
|
271
285
|
|
272
286
|
# Defines an attributes writer for the specified association(s).
|
273
287
|
#
|
@@ -317,7 +331,7 @@ module ActiveRecord
|
|
317
331
|
# # creates avatar_attributes= and posts_attributes=
|
318
332
|
# accepts_nested_attributes_for :avatar, :posts, allow_destroy: true
|
319
333
|
def accepts_nested_attributes_for(*attr_names)
|
320
|
-
options = { :
|
334
|
+
options = { allow_destroy: false, update_only: false }
|
321
335
|
options.update(attr_names.extract_options!)
|
322
336
|
options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only)
|
323
337
|
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
|
@@ -340,28 +354,25 @@ module ActiveRecord
|
|
340
354
|
end
|
341
355
|
|
342
356
|
private
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
end
|
363
|
-
eoruby
|
364
|
-
end
|
357
|
+
# Generates a writer method for this association. Serves as a point for
|
358
|
+
# accessing the objects in the association. For example, this method
|
359
|
+
# could generate the following:
|
360
|
+
#
|
361
|
+
# def pirate_attributes=(attributes)
|
362
|
+
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes)
|
363
|
+
# end
|
364
|
+
#
|
365
|
+
# This redirects the attempts to write objects in an association through
|
366
|
+
# the helper methods defined below. Makes it seem like the nested
|
367
|
+
# associations are just regular associations.
|
368
|
+
def generate_association_writer(association_name, type)
|
369
|
+
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
|
370
|
+
silence_redefinition_of_method :#{association_name}_attributes=
|
371
|
+
def #{association_name}_attributes=(attributes)
|
372
|
+
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
373
|
+
end
|
374
|
+
eoruby
|
375
|
+
end
|
365
376
|
end
|
366
377
|
|
367
378
|
# Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
|
@@ -374,214 +385,214 @@ module ActiveRecord
|
|
374
385
|
end
|
375
386
|
|
376
387
|
private
|
388
|
+
# Attribute hash keys that should not be assigned as normal attributes.
|
389
|
+
# These hash keys are nested attributes implementation details.
|
390
|
+
UNASSIGNABLE_KEYS = %w( id _destroy )
|
377
391
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
attributes = attributes.to_h
|
399
|
-
end
|
400
|
-
attributes = attributes.with_indifferent_access
|
401
|
-
existing_record = send(association_name)
|
392
|
+
# Assigns the given attributes to the association.
|
393
|
+
#
|
394
|
+
# If an associated record does not yet exist, one will be instantiated. If
|
395
|
+
# an associated record already exists, the method's behavior depends on
|
396
|
+
# the value of the update_only option. If update_only is +false+ and the
|
397
|
+
# given attributes include an <tt>:id</tt> that matches the existing record's
|
398
|
+
# id, then the existing record will be modified. If no <tt>:id</tt> is provided
|
399
|
+
# it will be replaced with a new record. If update_only is +true+ the existing
|
400
|
+
# record will be modified regardless of whether an <tt>:id</tt> is provided.
|
401
|
+
#
|
402
|
+
# If the given attributes include a matching <tt>:id</tt> attribute, or
|
403
|
+
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
|
404
|
+
# then the existing record will be marked for destruction.
|
405
|
+
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
406
|
+
options = nested_attributes_options[association_name]
|
407
|
+
if attributes.respond_to?(:permitted?)
|
408
|
+
attributes = attributes.to_h
|
409
|
+
end
|
410
|
+
attributes = attributes.with_indifferent_access
|
411
|
+
existing_record = send(association_name)
|
402
412
|
|
403
|
-
|
404
|
-
|
405
|
-
|
413
|
+
if (options[:update_only] || !attributes["id"].blank?) && existing_record &&
|
414
|
+
(options[:update_only] || existing_record.id.to_s == attributes["id"].to_s)
|
415
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
|
406
416
|
|
407
|
-
|
408
|
-
|
417
|
+
elsif attributes["id"].present?
|
418
|
+
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
409
419
|
|
410
|
-
|
411
|
-
|
420
|
+
elsif !reject_new_record?(association_name, attributes)
|
421
|
+
assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS)
|
412
422
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
else
|
417
|
-
method = "build_#{association_name}"
|
418
|
-
if respond_to?(method)
|
419
|
-
send(method, assignable_attributes)
|
423
|
+
if existing_record && existing_record.new_record?
|
424
|
+
existing_record.assign_attributes(assignable_attributes)
|
425
|
+
association(association_name).initialize_attributes(existing_record)
|
420
426
|
else
|
421
|
-
|
427
|
+
method = :"build_#{association_name}"
|
428
|
+
if respond_to?(method)
|
429
|
+
send(method, assignable_attributes)
|
430
|
+
else
|
431
|
+
raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?"
|
432
|
+
end
|
422
433
|
end
|
423
434
|
end
|
424
435
|
end
|
425
|
-
end
|
426
436
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
437
|
+
# Assigns the given attributes to the collection association.
|
438
|
+
#
|
439
|
+
# Hashes with an <tt>:id</tt> value matching an existing associated record
|
440
|
+
# will update that record. Hashes without an <tt>:id</tt> value will build
|
441
|
+
# a new record for the association. Hashes with a matching <tt>:id</tt>
|
442
|
+
# value and a <tt>:_destroy</tt> key set to a truthy value will mark the
|
443
|
+
# matched record for destruction.
|
444
|
+
#
|
445
|
+
# For example:
|
446
|
+
#
|
447
|
+
# assign_nested_attributes_for_collection_association(:people, {
|
448
|
+
# '1' => { id: '1', name: 'Peter' },
|
449
|
+
# '2' => { name: 'John' },
|
450
|
+
# '3' => { id: '2', _destroy: true }
|
451
|
+
# })
|
452
|
+
#
|
453
|
+
# Will update the name of the Person with ID 1, build a new associated
|
454
|
+
# person with the name 'John', and mark the associated Person with ID 2
|
455
|
+
# for destruction.
|
456
|
+
#
|
457
|
+
# Also accepts an Array of attribute hashes:
|
458
|
+
#
|
459
|
+
# assign_nested_attributes_for_collection_association(:people, [
|
460
|
+
# { id: '1', name: 'Peter' },
|
461
|
+
# { name: 'John' },
|
462
|
+
# { id: '2', _destroy: true }
|
463
|
+
# ])
|
464
|
+
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
465
|
+
options = nested_attributes_options[association_name]
|
466
|
+
if attributes_collection.respond_to?(:permitted?)
|
467
|
+
attributes_collection = attributes_collection.to_h
|
468
|
+
end
|
459
469
|
|
460
|
-
|
461
|
-
|
462
|
-
|
470
|
+
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
471
|
+
raise ArgumentError, "Hash or Array expected for attribute `#{association_name}`, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
|
472
|
+
end
|
463
473
|
|
464
|
-
|
474
|
+
check_record_limit!(options[:limit], attributes_collection)
|
465
475
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
476
|
+
if attributes_collection.is_a? Hash
|
477
|
+
keys = attributes_collection.keys
|
478
|
+
attributes_collection = if keys.include?("id") || keys.include?(:id)
|
479
|
+
[attributes_collection]
|
480
|
+
else
|
481
|
+
attributes_collection.values
|
482
|
+
end
|
472
483
|
end
|
473
|
-
end
|
474
|
-
|
475
|
-
association = association(association_name)
|
476
484
|
|
477
|
-
|
478
|
-
association.target
|
479
|
-
else
|
480
|
-
attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
|
481
|
-
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
482
|
-
end
|
485
|
+
association = association(association_name)
|
483
486
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
+
existing_records = if association.loaded?
|
488
|
+
association.target
|
489
|
+
else
|
490
|
+
attribute_ids = attributes_collection.map { |a| a["id"] || a[:id] }.compact
|
491
|
+
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
487
492
|
end
|
488
|
-
attributes = attributes.with_indifferent_access
|
489
493
|
|
490
|
-
|
491
|
-
|
492
|
-
|
494
|
+
attributes_collection.each do |attributes|
|
495
|
+
if attributes.respond_to?(:permitted?)
|
496
|
+
attributes = attributes.to_h
|
493
497
|
end
|
494
|
-
|
495
|
-
unless call_reject_if(association_name, attributes)
|
496
|
-
# Make sure we are operating on the actual object which is in the association's
|
497
|
-
# proxy_target array (either by finding it, or adding it if not found)
|
498
|
-
# Take into account that the proxy_target may have changed due to callbacks
|
499
|
-
target_record = association.target.detect { |record| record.id.to_s == attributes['id'].to_s }
|
500
|
-
if target_record
|
501
|
-
existing_record = target_record
|
502
|
-
else
|
503
|
-
association.add_to_target(existing_record, :skip_callbacks)
|
504
|
-
end
|
498
|
+
attributes = attributes.with_indifferent_access
|
505
499
|
|
506
|
-
|
500
|
+
if attributes["id"].blank?
|
501
|
+
unless reject_new_record?(association_name, attributes)
|
502
|
+
association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
|
503
|
+
end
|
504
|
+
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
|
505
|
+
unless call_reject_if(association_name, attributes)
|
506
|
+
# Make sure we are operating on the actual object which is in the association's
|
507
|
+
# proxy_target array (either by finding it, or adding it if not found)
|
508
|
+
# Take into account that the proxy_target may have changed due to callbacks
|
509
|
+
target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
|
510
|
+
if target_record
|
511
|
+
existing_record = target_record
|
512
|
+
else
|
513
|
+
association.add_to_target(existing_record, :skip_callbacks)
|
514
|
+
end
|
515
|
+
|
516
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
517
|
+
end
|
518
|
+
else
|
519
|
+
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
507
520
|
end
|
508
|
-
else
|
509
|
-
raise_nested_attributes_record_not_found!(association_name, attributes['id'])
|
510
521
|
end
|
511
522
|
end
|
512
|
-
end
|
513
523
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
524
|
+
# Takes in a limit and checks if the attributes_collection has too many
|
525
|
+
# records. It accepts limit in the form of symbol, proc, or
|
526
|
+
# number-like object (anything that can be compared with an integer).
|
527
|
+
#
|
528
|
+
# Raises TooManyRecords error if the attributes_collection is
|
529
|
+
# larger than the limit.
|
530
|
+
def check_record_limit!(limit, attributes_collection)
|
531
|
+
if limit
|
532
|
+
limit = \
|
533
|
+
case limit
|
534
|
+
when Symbol
|
535
|
+
send(limit)
|
536
|
+
when Proc
|
537
|
+
limit.call
|
538
|
+
else
|
539
|
+
limit
|
540
|
+
end
|
530
541
|
|
531
|
-
|
532
|
-
|
542
|
+
if limit && attributes_collection.size > limit
|
543
|
+
raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
|
544
|
+
end
|
533
545
|
end
|
534
546
|
end
|
535
|
-
end
|
536
547
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
548
|
+
# Updates a record with the +attributes+ or marks it for destruction if
|
549
|
+
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
|
550
|
+
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
|
551
|
+
record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
|
552
|
+
record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
|
553
|
+
end
|
543
554
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
555
|
+
# Determines if a hash contains a truthy _destroy key.
|
556
|
+
def has_destroy_flag?(hash)
|
557
|
+
Type::Boolean.new.cast(hash["_destroy"])
|
558
|
+
end
|
548
559
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
560
|
+
# Determines if a new record should be rejected by checking
|
561
|
+
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
562
|
+
# association and evaluates to +true+.
|
563
|
+
def reject_new_record?(association_name, attributes)
|
564
|
+
will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
|
565
|
+
end
|
555
566
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
567
|
+
# Determines if a record with the particular +attributes+ should be
|
568
|
+
# rejected by calling the reject_if Symbol or Proc (if defined).
|
569
|
+
# The reject_if option is defined by +accepts_nested_attributes_for+.
|
570
|
+
#
|
571
|
+
# Returns false if there is a +destroy_flag+ on the attributes.
|
572
|
+
def call_reject_if(association_name, attributes)
|
573
|
+
return false if will_be_destroyed?(association_name, attributes)
|
563
574
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
575
|
+
case callback = nested_attributes_options[association_name][:reject_if]
|
576
|
+
when Symbol
|
577
|
+
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
578
|
+
when Proc
|
579
|
+
callback.call(attributes)
|
580
|
+
end
|
569
581
|
end
|
570
|
-
end
|
571
582
|
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
583
|
+
# Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
|
584
|
+
def will_be_destroyed?(association_name, attributes)
|
585
|
+
allow_destroy?(association_name) && has_destroy_flag?(attributes)
|
586
|
+
end
|
576
587
|
|
577
|
-
|
578
|
-
|
579
|
-
|
588
|
+
def allow_destroy?(association_name)
|
589
|
+
nested_attributes_options[association_name][:allow_destroy]
|
590
|
+
end
|
580
591
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
592
|
+
def raise_nested_attributes_record_not_found!(association_name, record_id)
|
593
|
+
model = self.class._reflect_on_association(association_name).klass.name
|
594
|
+
raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
|
595
|
+
model, "id", record_id)
|
596
|
+
end
|
586
597
|
end
|
587
598
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record No Touching
|
3
5
|
module NoTouching
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
|
6
8
|
module ClassMethods
|
7
|
-
# Lets you selectively disable calls to
|
9
|
+
# Lets you selectively disable calls to +touch+ for the
|
8
10
|
# duration of a block.
|
9
11
|
#
|
10
12
|
# ==== Examples
|
@@ -41,15 +43,22 @@ module ActiveRecord
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
46
|
+
# Returns +true+ if the class has +no_touching+ set, +false+ otherwise.
|
47
|
+
#
|
48
|
+
# Project.no_touching do
|
49
|
+
# Project.first.no_touching? # true
|
50
|
+
# Message.first.no_touching? # false
|
51
|
+
# end
|
52
|
+
#
|
44
53
|
def no_touching?
|
45
54
|
NoTouching.applied_to?(self.class)
|
46
55
|
end
|
47
56
|
|
48
|
-
def touch_later(
|
57
|
+
def touch_later(*, **) # :nodoc:
|
49
58
|
super unless no_touching?
|
50
59
|
end
|
51
60
|
|
52
|
-
def touch(
|
61
|
+
def touch(*, **) # :nodoc:
|
53
62
|
super unless no_touching?
|
54
63
|
end
|
55
64
|
end
|
@@ -1,14 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module NullRelation # :nodoc:
|
3
|
-
def exec_queries
|
4
|
-
@records = [].freeze
|
5
|
-
end
|
6
|
-
|
7
5
|
def pluck(*column_names)
|
8
6
|
[]
|
9
7
|
end
|
10
8
|
|
11
|
-
def delete_all
|
9
|
+
def delete_all
|
12
10
|
0
|
13
11
|
end
|
14
12
|
|
@@ -20,10 +18,6 @@ module ActiveRecord
|
|
20
18
|
0
|
21
19
|
end
|
22
20
|
|
23
|
-
def size
|
24
|
-
calculate :size, nil
|
25
|
-
end
|
26
|
-
|
27
21
|
def empty?
|
28
22
|
true
|
29
23
|
end
|
@@ -48,33 +42,12 @@ module ActiveRecord
|
|
48
42
|
""
|
49
43
|
end
|
50
44
|
|
51
|
-
def count(*)
|
52
|
-
calculate :count, nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def sum(*)
|
56
|
-
calculate :sum, nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def average(*)
|
60
|
-
calculate :average, nil
|
61
|
-
end
|
62
|
-
|
63
|
-
def minimum(*)
|
64
|
-
calculate :minimum, nil
|
65
|
-
end
|
66
|
-
|
67
|
-
def maximum(*)
|
68
|
-
calculate :maximum, nil
|
69
|
-
end
|
70
|
-
|
71
45
|
def calculate(operation, _column_name)
|
72
|
-
|
46
|
+
case operation
|
47
|
+
when :count, :sum
|
73
48
|
group_values.any? ? Hash.new : 0
|
74
|
-
|
75
|
-
Hash.new
|
76
|
-
else
|
77
|
-
nil
|
49
|
+
when :average, :minimum, :maximum
|
50
|
+
group_values.any? ? Hash.new : nil
|
78
51
|
end
|
79
52
|
end
|
80
53
|
|
@@ -85,5 +58,10 @@ module ActiveRecord
|
|
85
58
|
def or(other)
|
86
59
|
other.spawn
|
87
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def exec_queries
|
64
|
+
@records = [].freeze
|
65
|
+
end
|
88
66
|
end
|
89
67
|
end
|