activerecord 5.0.6 → 6.0.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 +638 -2023
- data/MIT-LICENSE +3 -1
- data/README.rdoc +8 -6
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/aggregations.rb +249 -246
- data/lib/active_record/association_relation.rb +24 -13
- data/lib/active_record/associations/alias_tracker.rb +24 -33
- data/lib/active_record/associations/association.rb +119 -56
- data/lib/active_record/associations/association_scope.rb +94 -94
- 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 +42 -61
- 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 +80 -252
- data/lib/active_record/associations/collection_proxy.rb +158 -121
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -29
- 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 +38 -90
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -176
- data/lib/active_record/associations/preloader/association.rb +84 -125
- data/lib/active_record/associations/preloader/through_association.rb +82 -75
- data/lib/active_record/associations/preloader.rb +90 -102
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +26 -14
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -60
- data/lib/active_record/attribute_decorators.rb +38 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +86 -91
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +21 -49
- data/lib/active_record/attribute_methods/serialization.rb +30 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
- data/lib/active_record/attribute_methods/write.rb +35 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/autosave_association.rb +53 -32
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +63 -33
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
- 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 +143 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -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 +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -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 -10
- 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 +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
- 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 +45 -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 +31 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -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 +9 -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 +19 -25
- 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 +35 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -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 +120 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
- 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 +254 -262
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
- data/lib/active_record/connection_handling.rb +159 -40
- data/lib/active_record/core.rb +202 -162
- data/lib/active_record/counter_cache.rb +57 -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 +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 +87 -86
- data/lib/active_record/enum.rb +60 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -3
- 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 +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +195 -502
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +151 -97
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +15 -18
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +78 -87
- 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 +88 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +143 -97
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +367 -300
- data/lib/active_record/model_schema.rb +145 -139
- data/lib/active_record/nested_attributes.rb +214 -201
- data/lib/active_record/no_touching.rb +10 -1
- data/lib/active_record/null_relation.rb +13 -34
- data/lib/active_record/persistence.rb +442 -72
- data/lib/active_record/query_cache.rb +15 -14
- data/lib/active_record/querying.rb +36 -23
- 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 +309 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +211 -249
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +99 -52
- data/lib/active_record/relation/calculations.rb +211 -172
- data/lib/active_record/relation/delegation.rb +67 -65
- data/lib/active_record/relation/finder_methods.rb +208 -247
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +78 -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 +86 -104
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +458 -329
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -95
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +429 -318
- data/lib/active_record/result.rb +69 -39
- 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 +15 -5
- data/lib/active_record/scoping/default.rb +93 -95
- data/lib/active_record/scoping/named.rb +45 -25
- data/lib/active_record/scoping.rb +20 -19
- 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 +4 -1
- data/lib/active_record/table_metadata.rb +26 -20
- data/lib/active_record/tasks/database_tasks.rb +276 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
- data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +70 -35
- data/lib/active_record/touch_later.rb +7 -4
- data/lib/active_record/transactions.rb +133 -149
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -45
- 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 -3
- 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 -8
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +2 -1
- data/lib/active_record/type/type_map.rb +13 -15
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +23 -17
- 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 -1
- 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 -4
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -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 +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 +58 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- 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/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 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- 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 +133 -50
- 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 -130
- 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
@@ -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
|
@@ -341,27 +355,25 @@ module ActiveRecord
|
|
341
355
|
|
342
356
|
private
|
343
357
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
eoruby
|
364
|
-
end
|
358
|
+
# Generates a writer method for this association. Serves as a point for
|
359
|
+
# accessing the objects in the association. For example, this method
|
360
|
+
# could generate the following:
|
361
|
+
#
|
362
|
+
# def pirate_attributes=(attributes)
|
363
|
+
# assign_nested_attributes_for_one_to_one_association(:pirate, attributes)
|
364
|
+
# end
|
365
|
+
#
|
366
|
+
# This redirects the attempts to write objects in an association through
|
367
|
+
# the helper methods defined below. Makes it seem like the nested
|
368
|
+
# associations are just regular associations.
|
369
|
+
def generate_association_writer(association_name, type)
|
370
|
+
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
|
371
|
+
silence_redefinition_of_method :#{association_name}_attributes=
|
372
|
+
def #{association_name}_attributes=(attributes)
|
373
|
+
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
374
|
+
end
|
375
|
+
eoruby
|
376
|
+
end
|
365
377
|
end
|
366
378
|
|
367
379
|
# Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
|
@@ -375,213 +387,214 @@ module ActiveRecord
|
|
375
387
|
|
376
388
|
private
|
377
389
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
390
|
+
# Attribute hash keys that should not be assigned as normal attributes.
|
391
|
+
# These hash keys are nested attributes implementation details.
|
392
|
+
UNASSIGNABLE_KEYS = %w( id _destroy )
|
393
|
+
|
394
|
+
# Assigns the given attributes to the association.
|
395
|
+
#
|
396
|
+
# If an associated record does not yet exist, one will be instantiated. If
|
397
|
+
# an associated record already exists, the method's behavior depends on
|
398
|
+
# the value of the update_only option. If update_only is +false+ and the
|
399
|
+
# given attributes include an <tt>:id</tt> that matches the existing record's
|
400
|
+
# id, then the existing record will be modified. If no <tt>:id</tt> is provided
|
401
|
+
# it will be replaced with a new record. If update_only is +true+ the existing
|
402
|
+
# record will be modified regardless of whether an <tt>:id</tt> is provided.
|
403
|
+
#
|
404
|
+
# If the given attributes include a matching <tt>:id</tt> attribute, or
|
405
|
+
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
|
406
|
+
# then the existing record will be marked for destruction.
|
407
|
+
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
408
|
+
options = nested_attributes_options[association_name]
|
409
|
+
if attributes.respond_to?(:permitted?)
|
410
|
+
attributes = attributes.to_h
|
411
|
+
end
|
412
|
+
attributes = attributes.with_indifferent_access
|
413
|
+
existing_record = send(association_name)
|
402
414
|
|
403
|
-
|
404
|
-
|
405
|
-
|
415
|
+
if (options[:update_only] || !attributes["id"].blank?) && existing_record &&
|
416
|
+
(options[:update_only] || existing_record.id.to_s == attributes["id"].to_s)
|
417
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
|
406
418
|
|
407
|
-
|
408
|
-
|
419
|
+
elsif attributes["id"].present?
|
420
|
+
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
409
421
|
|
410
|
-
|
411
|
-
|
422
|
+
elsif !reject_new_record?(association_name, attributes)
|
423
|
+
assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS)
|
412
424
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
else
|
417
|
-
method = "build_#{association_name}"
|
418
|
-
if respond_to?(method)
|
419
|
-
send(method, assignable_attributes)
|
425
|
+
if existing_record && existing_record.new_record?
|
426
|
+
existing_record.assign_attributes(assignable_attributes)
|
427
|
+
association(association_name).initialize_attributes(existing_record)
|
420
428
|
else
|
421
|
-
|
429
|
+
method = :"build_#{association_name}"
|
430
|
+
if respond_to?(method)
|
431
|
+
send(method, assignable_attributes)
|
432
|
+
else
|
433
|
+
raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?"
|
434
|
+
end
|
422
435
|
end
|
423
436
|
end
|
424
437
|
end
|
425
|
-
end
|
426
438
|
|
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
|
-
|
439
|
+
# Assigns the given attributes to the collection association.
|
440
|
+
#
|
441
|
+
# Hashes with an <tt>:id</tt> value matching an existing associated record
|
442
|
+
# will update that record. Hashes without an <tt>:id</tt> value will build
|
443
|
+
# a new record for the association. Hashes with a matching <tt>:id</tt>
|
444
|
+
# value and a <tt>:_destroy</tt> key set to a truthy value will mark the
|
445
|
+
# matched record for destruction.
|
446
|
+
#
|
447
|
+
# For example:
|
448
|
+
#
|
449
|
+
# assign_nested_attributes_for_collection_association(:people, {
|
450
|
+
# '1' => { id: '1', name: 'Peter' },
|
451
|
+
# '2' => { name: 'John' },
|
452
|
+
# '3' => { id: '2', _destroy: true }
|
453
|
+
# })
|
454
|
+
#
|
455
|
+
# Will update the name of the Person with ID 1, build a new associated
|
456
|
+
# person with the name 'John', and mark the associated Person with ID 2
|
457
|
+
# for destruction.
|
458
|
+
#
|
459
|
+
# Also accepts an Array of attribute hashes:
|
460
|
+
#
|
461
|
+
# assign_nested_attributes_for_collection_association(:people, [
|
462
|
+
# { id: '1', name: 'Peter' },
|
463
|
+
# { name: 'John' },
|
464
|
+
# { id: '2', _destroy: true }
|
465
|
+
# ])
|
466
|
+
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
467
|
+
options = nested_attributes_options[association_name]
|
468
|
+
if attributes_collection.respond_to?(:permitted?)
|
469
|
+
attributes_collection = attributes_collection.to_h
|
470
|
+
end
|
459
471
|
|
460
|
-
|
461
|
-
|
462
|
-
|
472
|
+
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
473
|
+
raise ArgumentError, "Hash or Array expected for attribute `#{association_name}`, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
|
474
|
+
end
|
463
475
|
|
464
|
-
|
476
|
+
check_record_limit!(options[:limit], attributes_collection)
|
465
477
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
478
|
+
if attributes_collection.is_a? Hash
|
479
|
+
keys = attributes_collection.keys
|
480
|
+
attributes_collection = if keys.include?("id") || keys.include?(:id)
|
481
|
+
[attributes_collection]
|
482
|
+
else
|
483
|
+
attributes_collection.values
|
484
|
+
end
|
472
485
|
end
|
473
|
-
end
|
474
|
-
|
475
|
-
association = association(association_name)
|
476
486
|
|
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
|
487
|
+
association = association(association_name)
|
483
488
|
|
484
|
-
|
485
|
-
|
486
|
-
|
489
|
+
existing_records = if association.loaded?
|
490
|
+
association.target
|
491
|
+
else
|
492
|
+
attribute_ids = attributes_collection.map { |a| a["id"] || a[:id] }.compact
|
493
|
+
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
|
487
494
|
end
|
488
|
-
attributes = attributes.with_indifferent_access
|
489
495
|
|
490
|
-
|
491
|
-
|
492
|
-
|
496
|
+
attributes_collection.each do |attributes|
|
497
|
+
if attributes.respond_to?(:permitted?)
|
498
|
+
attributes = attributes.to_h
|
493
499
|
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
|
500
|
+
attributes = attributes.with_indifferent_access
|
505
501
|
|
506
|
-
|
502
|
+
if attributes["id"].blank?
|
503
|
+
unless reject_new_record?(association_name, attributes)
|
504
|
+
association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
|
505
|
+
end
|
506
|
+
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
|
507
|
+
unless call_reject_if(association_name, attributes)
|
508
|
+
# Make sure we are operating on the actual object which is in the association's
|
509
|
+
# proxy_target array (either by finding it, or adding it if not found)
|
510
|
+
# Take into account that the proxy_target may have changed due to callbacks
|
511
|
+
target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
|
512
|
+
if target_record
|
513
|
+
existing_record = target_record
|
514
|
+
else
|
515
|
+
association.add_to_target(existing_record, :skip_callbacks)
|
516
|
+
end
|
517
|
+
|
518
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
519
|
+
end
|
520
|
+
else
|
521
|
+
raise_nested_attributes_record_not_found!(association_name, attributes["id"])
|
507
522
|
end
|
508
|
-
else
|
509
|
-
raise_nested_attributes_record_not_found!(association_name, attributes['id'])
|
510
523
|
end
|
511
524
|
end
|
512
|
-
end
|
513
525
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
526
|
+
# Takes in a limit and checks if the attributes_collection has too many
|
527
|
+
# records. It accepts limit in the form of symbol, proc, or
|
528
|
+
# number-like object (anything that can be compared with an integer).
|
529
|
+
#
|
530
|
+
# Raises TooManyRecords error if the attributes_collection is
|
531
|
+
# larger than the limit.
|
532
|
+
def check_record_limit!(limit, attributes_collection)
|
533
|
+
if limit
|
534
|
+
limit = \
|
535
|
+
case limit
|
536
|
+
when Symbol
|
537
|
+
send(limit)
|
538
|
+
when Proc
|
539
|
+
limit.call
|
540
|
+
else
|
541
|
+
limit
|
542
|
+
end
|
530
543
|
|
531
|
-
|
532
|
-
|
544
|
+
if limit && attributes_collection.size > limit
|
545
|
+
raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
|
546
|
+
end
|
533
547
|
end
|
534
548
|
end
|
535
|
-
end
|
536
549
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
550
|
+
# Updates a record with the +attributes+ or marks it for destruction if
|
551
|
+
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
|
552
|
+
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
|
553
|
+
record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
|
554
|
+
record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
|
555
|
+
end
|
543
556
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
557
|
+
# Determines if a hash contains a truthy _destroy key.
|
558
|
+
def has_destroy_flag?(hash)
|
559
|
+
Type::Boolean.new.cast(hash["_destroy"])
|
560
|
+
end
|
548
561
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
562
|
+
# Determines if a new record should be rejected by checking
|
563
|
+
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
564
|
+
# association and evaluates to +true+.
|
565
|
+
def reject_new_record?(association_name, attributes)
|
566
|
+
will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
|
567
|
+
end
|
555
568
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
569
|
+
# Determines if a record with the particular +attributes+ should be
|
570
|
+
# rejected by calling the reject_if Symbol or Proc (if defined).
|
571
|
+
# The reject_if option is defined by +accepts_nested_attributes_for+.
|
572
|
+
#
|
573
|
+
# Returns false if there is a +destroy_flag+ on the attributes.
|
574
|
+
def call_reject_if(association_name, attributes)
|
575
|
+
return false if will_be_destroyed?(association_name, attributes)
|
563
576
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
577
|
+
case callback = nested_attributes_options[association_name][:reject_if]
|
578
|
+
when Symbol
|
579
|
+
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
580
|
+
when Proc
|
581
|
+
callback.call(attributes)
|
582
|
+
end
|
569
583
|
end
|
570
|
-
end
|
571
584
|
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
585
|
+
# Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
|
586
|
+
def will_be_destroyed?(association_name, attributes)
|
587
|
+
allow_destroy?(association_name) && has_destroy_flag?(attributes)
|
588
|
+
end
|
576
589
|
|
577
|
-
|
578
|
-
|
579
|
-
|
590
|
+
def allow_destroy?(association_name)
|
591
|
+
nested_attributes_options[association_name][:allow_destroy]
|
592
|
+
end
|
580
593
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
594
|
+
def raise_nested_attributes_record_not_found!(association_name, record_id)
|
595
|
+
model = self.class._reflect_on_association(association_name).klass.name
|
596
|
+
raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
|
597
|
+
model, "id", record_id)
|
598
|
+
end
|
586
599
|
end
|
587
600
|
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,6 +43,13 @@ 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
|
@@ -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,11 @@ module ActiveRecord
|
|
85
58
|
def or(other)
|
86
59
|
other.spawn
|
87
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def exec_queries
|
65
|
+
@records = [].freeze
|
66
|
+
end
|
88
67
|
end
|
89
68
|
end
|