activerecord 4.2.11.3 → 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 +4 -4
- data/CHANGELOG.md +613 -1643
- data/MIT-LICENSE +4 -2
- data/README.rdoc +13 -12
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record.rb +41 -22
- data/lib/active_record/aggregations.rb +267 -251
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +125 -58
- data/lib/active_record/associations/association_scope.rb +103 -132
- data/lib/active_record/associations/belongs_to_association.rb +65 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +27 -40
- data/lib/active_record/associations/builder/belongs_to.rb +69 -55
- data/lib/active_record/associations/builder/collection_association.rb +10 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
- data/lib/active_record/associations/builder/has_many.rb +8 -4
- data/lib/active_record/associations/builder/has_one.rb +46 -5
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +131 -287
- data/lib/active_record/associations/collection_proxy.rb +241 -146
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -97
- data/lib/active_record/associations/has_many_through_association.rb +60 -87
- data/lib/active_record/associations/has_one_association.rb +61 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +137 -167
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
- 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/preloader.rb +90 -92
- data/lib/active_record/associations/preloader/association.rb +90 -123
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/attribute_assignment.rb +56 -183
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- data/lib/active_record/attribute_methods/primary_key.rb +91 -83
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -76
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
- data/lib/active_record/attribute_methods/write.rb +32 -54
- data/lib/active_record/attributes.rb +214 -82
- data/lib/active_record/autosave_association.rb +91 -37
- data/lib/active_record/base.rb +57 -45
- data/lib/active_record/callbacks.rb +100 -74
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
- data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
- 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 +58 -180
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
- 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 +31 -19
- 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 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
- data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
- 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 +290 -345
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +176 -41
- data/lib/active_record/core.rb +251 -231
- data/lib/active_record/counter_cache.rb +67 -49
- data/lib/active_record/database_configurations.rb +233 -0
- 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/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -53
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- 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 +228 -499
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +158 -112
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +123 -29
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +87 -96
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +76 -33
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +621 -303
- data/lib/active_record/migration/command_recorder.rb +177 -90
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/model_schema.rb +312 -112
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +14 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +557 -125
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +43 -29
- data/lib/active_record/railtie.rb +143 -44
- 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 +328 -185
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +428 -279
- data/lib/active_record/relation.rb +518 -341
- data/lib/active_record/relation/batches.rb +207 -55
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +267 -253
- data/lib/active_record/relation/delegation.rb +70 -80
- data/lib/active_record/relation/finder_methods.rb +277 -241
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +78 -87
- data/lib/active_record/relation/predicate_builder.rb +114 -119
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
- 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 +7 -1
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +575 -394
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- 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/result.rb +79 -42
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +144 -121
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +112 -93
- data/lib/active_record/schema_migration.rb +24 -17
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/scoping/default.rb +101 -85
- data/lib/active_record/scoping/named.rb +86 -33
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +73 -36
- data/lib/active_record/store.rb +127 -42
- 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 +307 -100
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
- data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -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 +86 -40
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +216 -150
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +78 -23
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- 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 +24 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type_caster.rb +9 -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/validations.rb +39 -35
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +42 -55
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/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.rb +20 -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/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- 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.rb +31 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
- 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 → migration.rb.tt} +11 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +19 -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} +0 -0
- metadata +164 -59
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require 'thread_safe'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mutex_m"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
6
|
# = Active Record Attribute Methods
|
@@ -23,43 +22,12 @@ module ActiveRecord
|
|
23
22
|
delegate :column_for_attribute, to: :class
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
|
-
def self.set_name_cache(name, value)
|
28
|
-
const_name = "ATTR_#{name}"
|
29
|
-
unless const_defined? const_name
|
30
|
-
const_set const_name, value.dup.freeze
|
31
|
-
end
|
32
|
-
end
|
33
|
-
}
|
34
|
-
|
35
|
-
BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
25
|
+
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
36
26
|
|
37
|
-
class
|
38
|
-
|
39
|
-
@module = Module.new
|
40
|
-
@method_cache = ThreadSafe::Cache.new
|
41
|
-
end
|
42
|
-
|
43
|
-
def [](name)
|
44
|
-
@method_cache.compute_if_absent(name) do
|
45
|
-
safe_name = name.unpack('h*').first
|
46
|
-
temp_method = "__temp__#{safe_name}"
|
47
|
-
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
48
|
-
@module.module_eval method_body(temp_method, safe_name), __FILE__, __LINE__
|
49
|
-
@module.instance_method temp_method
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
# Override this method in the subclasses for method body.
|
56
|
-
def method_body(method_name, const_name)
|
57
|
-
raise NotImplementedError, "Subclasses must implement a method_body(method_name, const_name) method."
|
58
|
-
end
|
27
|
+
class GeneratedAttributeMethods < Module #:nodoc:
|
28
|
+
include Mutex_m
|
59
29
|
end
|
60
30
|
|
61
|
-
class GeneratedAttributeMethods < Module; end # :nodoc:
|
62
|
-
|
63
31
|
module ClassMethods
|
64
32
|
def inherited(child_class) #:nodoc:
|
65
33
|
child_class.initialize_generated_modules
|
@@ -67,7 +35,8 @@ module ActiveRecord
|
|
67
35
|
end
|
68
36
|
|
69
37
|
def initialize_generated_modules # :nodoc:
|
70
|
-
@generated_attribute_methods = GeneratedAttributeMethods.new
|
38
|
+
@generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
|
39
|
+
private_constant :GeneratedAttributeMethods
|
71
40
|
@attribute_methods_generated = false
|
72
41
|
include @generated_attribute_methods
|
73
42
|
|
@@ -82,11 +51,10 @@ module ActiveRecord
|
|
82
51
|
# attribute methods.
|
83
52
|
generated_attribute_methods.synchronize do
|
84
53
|
return false if @attribute_methods_generated
|
85
|
-
superclass.define_attribute_methods unless
|
86
|
-
super(
|
54
|
+
superclass.define_attribute_methods unless base_class?
|
55
|
+
super(attribute_names)
|
87
56
|
@attribute_methods_generated = true
|
88
57
|
end
|
89
|
-
true
|
90
58
|
end
|
91
59
|
|
92
60
|
def undefine_attribute_methods # :nodoc:
|
@@ -96,7 +64,7 @@ module ActiveRecord
|
|
96
64
|
end
|
97
65
|
end
|
98
66
|
|
99
|
-
# Raises
|
67
|
+
# Raises an ActiveRecord::DangerousAttributeError exception when an
|
100
68
|
# \Active \Record method is defined in the model, otherwise +false+.
|
101
69
|
#
|
102
70
|
# class Person < ActiveRecord::Base
|
@@ -106,7 +74,7 @@ module ActiveRecord
|
|
106
74
|
# end
|
107
75
|
#
|
108
76
|
# Person.instance_method_already_implemented?(:save)
|
109
|
-
# # => ActiveRecord::DangerousAttributeError: save is defined by
|
77
|
+
# # => ActiveRecord::DangerousAttributeError: save is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.
|
110
78
|
#
|
111
79
|
# Person.instance_method_already_implemented?(:name)
|
112
80
|
# # => false
|
@@ -147,10 +115,10 @@ module ActiveRecord
|
|
147
115
|
# A class method is 'dangerous' if it is already (re)defined by Active Record, but
|
148
116
|
# not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
|
149
117
|
def dangerous_class_method?(method_name)
|
150
|
-
|
118
|
+
RESTRICTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
|
151
119
|
end
|
152
120
|
|
153
|
-
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc
|
121
|
+
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
154
122
|
if klass.respond_to?(name, true)
|
155
123
|
if superklass.respond_to?(name, true)
|
156
124
|
klass.method(name).owner != superklass.method(name).owner
|
@@ -172,7 +140,7 @@ module ActiveRecord
|
|
172
140
|
# Person.attribute_method?(:age=) # => true
|
173
141
|
# Person.attribute_method?(:nothing) # => false
|
174
142
|
def attribute_method?(attribute)
|
175
|
-
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/,
|
143
|
+
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, "")))
|
176
144
|
end
|
177
145
|
|
178
146
|
# Returns an array of column names as strings if it's not an abstract class and
|
@@ -185,14 +153,27 @@ module ActiveRecord
|
|
185
153
|
# # => ["id", "created_at", "updated_at", "name", "age"]
|
186
154
|
def attribute_names
|
187
155
|
@attribute_names ||= if !abstract_class? && table_exists?
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
156
|
+
attribute_types.keys
|
157
|
+
else
|
158
|
+
[]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns true if the given attribute exists, otherwise false.
|
163
|
+
#
|
164
|
+
# class Person < ActiveRecord::Base
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# Person.has_attribute?('name') # => true
|
168
|
+
# Person.has_attribute?(:age) # => true
|
169
|
+
# Person.has_attribute?(:nothing) # => false
|
170
|
+
def has_attribute?(attr_name)
|
171
|
+
attribute_types.key?(attr_name.to_s)
|
192
172
|
end
|
193
173
|
|
194
174
|
# Returns the column object for the named attribute.
|
195
|
-
# Returns
|
175
|
+
# Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
|
176
|
+
# named attribute does not exist.
|
196
177
|
#
|
197
178
|
# class Person < ActiveRecord::Base
|
198
179
|
# end
|
@@ -202,49 +183,45 @@ module ActiveRecord
|
|
202
183
|
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
203
184
|
#
|
204
185
|
# person.column_for_attribute(:nothing)
|
205
|
-
# # => nil
|
186
|
+
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
206
187
|
def column_for_attribute(name)
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
`#column_for_attribute` will return a null object for non-existent
|
211
|
-
columns in Rails 5. Use `#has_attribute?` if you need to check for
|
212
|
-
an attribute's existence.
|
213
|
-
MSG
|
188
|
+
name = name.to_s
|
189
|
+
columns_hash.fetch(name) do
|
190
|
+
ConnectionAdapters::NullColumn.new(name)
|
214
191
|
end
|
215
|
-
column
|
216
192
|
end
|
217
193
|
end
|
218
194
|
|
219
195
|
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
|
220
196
|
# <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
|
221
|
-
# which will all return +true+. It also
|
197
|
+
# which will all return +true+. It also defines the attribute methods if they have
|
222
198
|
# not been generated.
|
223
199
|
#
|
224
200
|
# class Person < ActiveRecord::Base
|
225
201
|
# end
|
226
202
|
#
|
227
203
|
# person = Person.new
|
228
|
-
# person.respond_to(:name) # => true
|
229
|
-
# person.respond_to(:name=) # => true
|
230
|
-
# person.respond_to(:name?) # => true
|
231
|
-
# person.respond_to('age') # => true
|
232
|
-
# person.respond_to('age=') # => true
|
233
|
-
# person.respond_to('age?') # => true
|
234
|
-
# person.respond_to(:nothing) # => false
|
204
|
+
# person.respond_to?(:name) # => true
|
205
|
+
# person.respond_to?(:name=) # => true
|
206
|
+
# person.respond_to?(:name?) # => true
|
207
|
+
# person.respond_to?('age') # => true
|
208
|
+
# person.respond_to?('age=') # => true
|
209
|
+
# person.respond_to?('age?') # => true
|
210
|
+
# person.respond_to?(:nothing) # => false
|
235
211
|
def respond_to?(name, include_private = false)
|
236
212
|
return false unless super
|
237
|
-
name = name.to_s
|
238
213
|
|
239
214
|
# If the result is true then check for the select case.
|
240
215
|
# For queries selecting a subset of columns, return false for unselected columns.
|
241
216
|
# We check defined?(@attributes) not to issue warnings if called on objects that
|
242
217
|
# have been allocated but not yet initialized.
|
243
|
-
if defined?(@attributes)
|
244
|
-
|
218
|
+
if defined?(@attributes)
|
219
|
+
if name = self.class.symbol_column_to_string(name.to_sym)
|
220
|
+
return has_attribute?(name)
|
221
|
+
end
|
245
222
|
end
|
246
223
|
|
247
|
-
|
224
|
+
true
|
248
225
|
end
|
249
226
|
|
250
227
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
@@ -301,15 +278,8 @@ module ActiveRecord
|
|
301
278
|
# person.attribute_for_inspect(:tag_ids)
|
302
279
|
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
303
280
|
def attribute_for_inspect(attr_name)
|
304
|
-
value =
|
305
|
-
|
306
|
-
if value.is_a?(String) && value.length > 50
|
307
|
-
"#{value[0, 50]}...".inspect
|
308
|
-
elsif value.is_a?(Date) || value.is_a?(Time)
|
309
|
-
%("#{value.to_s(:db)}")
|
310
|
-
else
|
311
|
-
value.inspect
|
312
|
-
end
|
281
|
+
value = _read_attribute(attr_name)
|
282
|
+
format_for_inspect(value)
|
313
283
|
end
|
314
284
|
|
315
285
|
# Returns +true+ if the specified +attribute+ has been set by the user or by a
|
@@ -338,8 +308,6 @@ module ActiveRecord
|
|
338
308
|
#
|
339
309
|
# Note: +:id+ is always present.
|
340
310
|
#
|
341
|
-
# Alias for the <tt>read_attribute</tt> method.
|
342
|
-
#
|
343
311
|
# class Person < ActiveRecord::Base
|
344
312
|
# belongs_to :organization
|
345
313
|
# end
|
@@ -356,7 +324,7 @@ module ActiveRecord
|
|
356
324
|
end
|
357
325
|
|
358
326
|
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
359
|
-
# (Alias for the protected
|
327
|
+
# (Alias for the protected #write_attribute method).
|
360
328
|
#
|
361
329
|
# class Person < ActiveRecord::Base
|
362
330
|
# end
|
@@ -369,67 +337,84 @@ module ActiveRecord
|
|
369
337
|
write_attribute(attr_name, value)
|
370
338
|
end
|
371
339
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
def
|
390
|
-
|
391
|
-
|
340
|
+
# Returns the name of all database fields which have been read from this
|
341
|
+
# model. This can be useful in development mode to determine which fields
|
342
|
+
# need to be selected. For performance critical pages, selecting only the
|
343
|
+
# required fields can be an easy performance win (assuming you aren't using
|
344
|
+
# all of the fields on the model).
|
345
|
+
#
|
346
|
+
# For example:
|
347
|
+
#
|
348
|
+
# class PostsController < ActionController::Base
|
349
|
+
# after_action :print_accessed_fields, only: :index
|
350
|
+
#
|
351
|
+
# def index
|
352
|
+
# @posts = Post.all
|
353
|
+
# end
|
354
|
+
#
|
355
|
+
# private
|
356
|
+
#
|
357
|
+
# def print_accessed_fields
|
358
|
+
# p @posts.first.accessed_fields
|
359
|
+
# end
|
360
|
+
# end
|
361
|
+
#
|
362
|
+
# Which allows you to quickly change your code to:
|
363
|
+
#
|
364
|
+
# class PostsController < ActionController::Base
|
365
|
+
# def index
|
366
|
+
# @posts = Post.select(:id, :title, :author_id, :updated_at)
|
367
|
+
# end
|
368
|
+
# end
|
369
|
+
def accessed_fields
|
370
|
+
@attributes.accessed
|
392
371
|
end
|
393
372
|
|
394
373
|
private
|
374
|
+
def attribute_method?(attr_name)
|
375
|
+
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
376
|
+
defined?(@attributes) && @attributes.key?(attr_name)
|
377
|
+
end
|
395
378
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
arel_table = self.class.arel_table
|
401
|
-
|
402
|
-
attribute_names.each do |name|
|
403
|
-
attrs[arel_table[name]] = typecasted_attribute_value(name)
|
379
|
+
def attributes_with_values(attribute_names)
|
380
|
+
attribute_names.each_with_object({}) do |name, attrs|
|
381
|
+
attrs[name] = _read_attribute(name)
|
382
|
+
end
|
404
383
|
end
|
405
|
-
attrs
|
406
|
-
end
|
407
384
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
385
|
+
# Filters the primary keys and readonly attributes from the attribute names.
|
386
|
+
def attributes_for_update(attribute_names)
|
387
|
+
attribute_names &= self.class.column_names
|
388
|
+
attribute_names.delete_if do |name|
|
389
|
+
readonly_attribute?(name)
|
390
|
+
end
|
412
391
|
end
|
413
|
-
end
|
414
392
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
393
|
+
# Filters out the primary keys, from the attribute names, when the primary
|
394
|
+
# key is to be generated (e.g. the id attribute has no value).
|
395
|
+
def attributes_for_create(attribute_names)
|
396
|
+
attribute_names &= self.class.column_names
|
397
|
+
attribute_names.delete_if do |name|
|
398
|
+
pk_attribute?(name) && id.nil?
|
399
|
+
end
|
420
400
|
end
|
421
|
-
end
|
422
401
|
|
423
|
-
|
424
|
-
|
425
|
-
|
402
|
+
def format_for_inspect(value)
|
403
|
+
if value.is_a?(String) && value.length > 50
|
404
|
+
"#{value[0, 50]}...".inspect
|
405
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
406
|
+
%("#{value.to_s(:db)}")
|
407
|
+
else
|
408
|
+
value.inspect
|
409
|
+
end
|
410
|
+
end
|
426
411
|
|
427
|
-
|
428
|
-
|
429
|
-
|
412
|
+
def readonly_attribute?(name)
|
413
|
+
self.class.readonly_attributes.include?(name)
|
414
|
+
end
|
430
415
|
|
431
|
-
|
432
|
-
|
433
|
-
|
416
|
+
def pk_attribute?(name)
|
417
|
+
name == @primary_key
|
418
|
+
end
|
434
419
|
end
|
435
420
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
# = Active Record Attribute Methods Before Type Cast
|
4
6
|
#
|
5
|
-
#
|
7
|
+
# ActiveRecord::AttributeMethods::BeforeTypeCast provides a way to
|
6
8
|
# read the value of the attributes before typecasting and deserialization.
|
7
9
|
#
|
8
10
|
# class Task < ActiveRecord::Base
|
@@ -44,6 +46,7 @@ module ActiveRecord
|
|
44
46
|
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
|
45
47
|
# task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
|
46
48
|
def read_attribute_before_type_cast(attr_name)
|
49
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
47
50
|
@attributes[attr_name.to_s].value_before_type_cast
|
48
51
|
end
|
49
52
|
|
@@ -58,19 +61,21 @@ module ActiveRecord
|
|
58
61
|
# task.attributes_before_type_cast
|
59
62
|
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
|
60
63
|
def attributes_before_type_cast
|
64
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
61
65
|
@attributes.values_before_type_cast
|
62
66
|
end
|
63
67
|
|
64
68
|
private
|
65
69
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
# Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
|
71
|
+
def attribute_before_type_cast(attribute_name)
|
72
|
+
read_attribute_before_type_cast(attribute_name)
|
73
|
+
end
|
70
74
|
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
def attribute_came_from_user?(attribute_name)
|
76
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
77
|
+
@attributes[attribute_name].came_from_user?
|
78
|
+
end
|
74
79
|
end
|
75
80
|
end
|
76
81
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module AttributeMethods
|
5
|
-
module Dirty
|
7
|
+
module Dirty
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
8
10
|
include ActiveModel::Dirty
|
@@ -12,180 +14,208 @@ module ActiveRecord
|
|
12
14
|
raise "You cannot include Dirty after Timestamp"
|
13
15
|
end
|
14
16
|
|
15
|
-
class_attribute :partial_writes, instance_writer: false
|
16
|
-
self.partial_writes = true
|
17
|
-
end
|
17
|
+
class_attribute :partial_writes, instance_writer: false, default: true
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
status
|
25
|
-
end
|
19
|
+
# Attribute methods for "changed in last call to save?"
|
20
|
+
attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
|
21
|
+
attribute_method_prefix("saved_change_to_")
|
22
|
+
attribute_method_suffix("_before_last_save")
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
changes_applied
|
31
|
-
end
|
24
|
+
# Attribute methods for "will change if I call save?"
|
25
|
+
attribute_method_affix(prefix: "will_save_change_to_", suffix: "?")
|
26
|
+
attribute_method_suffix("_change_to_be_saved", "_in_database")
|
32
27
|
end
|
33
28
|
|
34
29
|
# <tt>reload</tt> the record and clears changed attributes.
|
35
30
|
def reload(*)
|
36
31
|
super.tap do
|
37
|
-
|
32
|
+
@mutations_before_last_save = nil
|
33
|
+
@mutations_from_database = nil
|
38
34
|
end
|
39
35
|
end
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
37
|
+
# Did this attribute change when we last saved?
|
38
|
+
#
|
39
|
+
# This method is useful in after callbacks to determine if an attribute
|
40
|
+
# was changed during the save that triggered the callbacks to run. It can
|
41
|
+
# be invoked as +saved_change_to_name?+ instead of
|
42
|
+
# <tt>saved_change_to_attribute?("name")</tt>.
|
43
|
+
#
|
44
|
+
# ==== Options
|
45
|
+
#
|
46
|
+
# +from+ When passed, this method will return false unless the original
|
47
|
+
# value is equal to the given option
|
48
|
+
#
|
49
|
+
# +to+ When passed, this method will return false unless the value was
|
50
|
+
# changed to the given value
|
51
|
+
def saved_change_to_attribute?(attr_name, **options)
|
52
|
+
mutations_before_last_save.changed?(attr_name.to_s, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the change to an attribute during the last save. If the
|
56
|
+
# attribute was changed, the result will be an array containing the
|
57
|
+
# original value and the saved value.
|
58
|
+
#
|
59
|
+
# This method is useful in after callbacks, to see the change in an
|
60
|
+
# attribute during the save that triggered the callbacks to run. It can be
|
61
|
+
# invoked as +saved_change_to_name+ instead of
|
62
|
+
# <tt>saved_change_to_attribute("name")</tt>.
|
63
|
+
def saved_change_to_attribute(attr_name)
|
64
|
+
mutations_before_last_save.change_to_attribute(attr_name.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the original value of an attribute before the last save.
|
68
|
+
#
|
69
|
+
# This method is useful in after callbacks to get the original value of an
|
70
|
+
# attribute before the save that triggered the callbacks to run. It can be
|
71
|
+
# invoked as +name_before_last_save+ instead of
|
72
|
+
# <tt>attribute_before_last_save("name")</tt>.
|
73
|
+
def attribute_before_last_save(attr_name)
|
74
|
+
mutations_before_last_save.original_value(attr_name.to_s)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Did the last call to +save+ have any changes to change?
|
78
|
+
def saved_changes?
|
79
|
+
mutations_before_last_save.any_changes?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns a hash containing all the changes that were just saved.
|
83
|
+
def saved_changes
|
84
|
+
mutations_before_last_save.changes
|
85
|
+
end
|
86
|
+
|
87
|
+
# Will this attribute change the next time we save?
|
88
|
+
#
|
89
|
+
# This method is useful in validations and before callbacks to determine
|
90
|
+
# if the next call to +save+ will change a particular attribute. It can be
|
91
|
+
# invoked as +will_save_change_to_name?+ instead of
|
92
|
+
# <tt>will_save_change_to_attribute("name")</tt>.
|
93
|
+
#
|
94
|
+
# ==== Options
|
95
|
+
#
|
96
|
+
# +from+ When passed, this method will return false unless the original
|
97
|
+
# value is equal to the given option
|
98
|
+
#
|
99
|
+
# +to+ When passed, this method will return false unless the value will be
|
100
|
+
# changed to the given value
|
101
|
+
def will_save_change_to_attribute?(attr_name, **options)
|
102
|
+
mutations_from_database.changed?(attr_name.to_s, options)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the change to an attribute that will be persisted during the
|
106
|
+
# next save.
|
107
|
+
#
|
108
|
+
# This method is useful in validations and before callbacks, to see the
|
109
|
+
# change to an attribute that will occur when the record is saved. It can
|
110
|
+
# be invoked as +name_change_to_be_saved+ instead of
|
111
|
+
# <tt>attribute_change_to_be_saved("name")</tt>.
|
112
|
+
#
|
113
|
+
# If the attribute will change, the result will be an array containing the
|
114
|
+
# original value and the new value about to be saved.
|
115
|
+
def attribute_change_to_be_saved(attr_name)
|
116
|
+
mutations_from_database.change_to_attribute(attr_name.to_s)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns the value of an attribute in the database, as opposed to the
|
120
|
+
# in-memory value that will be persisted the next time the record is
|
121
|
+
# saved.
|
122
|
+
#
|
123
|
+
# This method is useful in validations and before callbacks, to see the
|
124
|
+
# original value of an attribute prior to any changes about to be
|
125
|
+
# saved. It can be invoked as +name_in_database+ instead of
|
126
|
+
# <tt>attribute_in_database("name")</tt>.
|
127
|
+
def attribute_in_database(attr_name)
|
128
|
+
mutations_from_database.original_value(attr_name.to_s)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Will the next call to +save+ have any changes to persist?
|
132
|
+
def has_changes_to_save?
|
133
|
+
mutations_from_database.any_changes?
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns a hash containing all the changes that will be persisted during
|
137
|
+
# the next save.
|
138
|
+
def changes_to_save
|
139
|
+
mutations_from_database.changes
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns an array of the names of any attributes that will change when
|
143
|
+
# the record is next saved.
|
144
|
+
def changed_attribute_names_to_save
|
145
|
+
mutations_from_database.changed_attribute_names
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a hash of the attributes that will change when the record is
|
149
|
+
# next saved.
|
150
|
+
#
|
151
|
+
# The hash keys are the attribute names, and the hash values are the
|
152
|
+
# original attribute values in the database (as opposed to the in-memory
|
153
|
+
# values about to be saved).
|
154
|
+
def attributes_in_database
|
155
|
+
mutations_from_database.changed_values
|
50
156
|
end
|
51
157
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def changed_attributes
|
58
|
-
# This should only be set by methods which will call changed_attributes
|
59
|
-
# multiple times when it is known that the computed value cannot change.
|
60
|
-
if defined?(@cached_changed_attributes)
|
61
|
-
@cached_changed_attributes
|
62
|
-
else
|
63
|
-
super.reverse_merge(attributes_changed_in_place).freeze
|
158
|
+
private
|
159
|
+
def mutations_from_database
|
160
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
161
|
+
super
|
64
162
|
end
|
65
|
-
end
|
66
163
|
|
67
|
-
|
68
|
-
|
164
|
+
def mutations_before_last_save
|
165
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
69
166
|
super
|
70
167
|
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def attribute_changed_in_place?(attr_name)
|
74
|
-
old_value = original_raw_attribute(attr_name)
|
75
|
-
@attributes[attr_name].changed_in_place_from?(old_value)
|
76
|
-
end
|
77
168
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
def calculate_changes_from_defaults
|
85
|
-
@changed_attributes = nil
|
86
|
-
self.class.column_defaults.each do |attr, orig_value|
|
87
|
-
set_attribute_was(attr, orig_value) if _field_changed?(attr, orig_value)
|
169
|
+
def write_attribute_without_type_cast(attr_name, value)
|
170
|
+
result = super
|
171
|
+
clear_attribute_change(attr_name)
|
172
|
+
result
|
88
173
|
end
|
89
|
-
end
|
90
174
|
|
91
|
-
|
92
|
-
|
93
|
-
attr = attr.to_s
|
175
|
+
def _touch_row(attribute_names, time)
|
176
|
+
@_touch_attr_names = Set.new(attribute_names)
|
94
177
|
|
95
|
-
|
178
|
+
affected_rows = super
|
96
179
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
180
|
+
if @_skip_dirty_tracking ||= false
|
181
|
+
clear_attribute_changes(@_touch_attr_names)
|
182
|
+
return affected_rows
|
183
|
+
end
|
102
184
|
|
103
|
-
|
104
|
-
|
185
|
+
changes = {}
|
186
|
+
@attributes.keys.each do |attr_name|
|
187
|
+
next if @_touch_attr_names.include?(attr_name)
|
105
188
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
189
|
+
if attribute_changed?(attr_name)
|
190
|
+
changes[attr_name] = _read_attribute(attr_name)
|
191
|
+
_write_attribute(attr_name, attribute_was(attr_name))
|
192
|
+
clear_attribute_change(attr_name)
|
193
|
+
end
|
194
|
+
end
|
110
195
|
|
111
|
-
|
112
|
-
|
113
|
-
if attribute_changed_by_setter?(attr)
|
114
|
-
clear_attribute_changes(attr) unless _field_changed?(attr, old_value)
|
115
|
-
else
|
116
|
-
set_attribute_was(attr, old_value) if _field_changed?(attr, old_value)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def old_attribute_value(attr)
|
121
|
-
if attribute_changed?(attr)
|
122
|
-
changed_attributes[attr]
|
123
|
-
else
|
124
|
-
clone_attribute_value(:_read_attribute, attr)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def _update_record(*)
|
129
|
-
partial_writes? ? super(keys_for_partial_write) : super
|
130
|
-
end
|
131
|
-
|
132
|
-
def _create_record(*)
|
133
|
-
partial_writes? ? super(keys_for_partial_write) : super
|
134
|
-
end
|
135
|
-
|
136
|
-
# Serialized attributes should always be written in case they've been
|
137
|
-
# changed in place.
|
138
|
-
def keys_for_partial_write
|
139
|
-
changed & persistable_attribute_names
|
140
|
-
end
|
141
|
-
|
142
|
-
def _field_changed?(attr, old_value)
|
143
|
-
@attributes[attr].changed_from?(old_value)
|
144
|
-
end
|
196
|
+
changes_applied
|
197
|
+
changes.each { |attr_name, value| _write_attribute(attr_name, value) }
|
145
198
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
h[attr_name] = orig
|
199
|
+
affected_rows
|
200
|
+
ensure
|
201
|
+
@_touch_attr_names, @_skip_dirty_tracking = nil, nil
|
150
202
|
end
|
151
|
-
end
|
152
203
|
|
153
|
-
|
154
|
-
|
155
|
-
|
204
|
+
def _update_record(attribute_names = attribute_names_for_partial_writes)
|
205
|
+
affected_rows = super
|
206
|
+
changes_applied
|
207
|
+
affected_rows
|
156
208
|
end
|
157
|
-
end
|
158
209
|
|
159
|
-
|
160
|
-
|
161
|
-
|
210
|
+
def _create_record(attribute_names = attribute_names_for_partial_writes)
|
211
|
+
id = super
|
212
|
+
changes_applied
|
213
|
+
id
|
162
214
|
end
|
163
|
-
end
|
164
215
|
|
165
|
-
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
def store_original_raw_attribute(attr_name)
|
170
|
-
original_raw_attributes[attr_name] = @attributes[attr_name].value_for_database rescue nil
|
171
|
-
end
|
172
|
-
|
173
|
-
def store_original_raw_attributes
|
174
|
-
attribute_names.each do |attr|
|
175
|
-
store_original_raw_attribute(attr)
|
216
|
+
def attribute_names_for_partial_writes
|
217
|
+
partial_writes? ? changed_attribute_names_to_save : attribute_names
|
176
218
|
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def cache_changed_attributes
|
180
|
-
@cached_changed_attributes = changed_attributes
|
181
|
-
yield
|
182
|
-
ensure
|
183
|
-
clear_changed_attributes_cache
|
184
|
-
end
|
185
|
-
|
186
|
-
def clear_changed_attributes_cache
|
187
|
-
remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
|
188
|
-
end
|
189
219
|
end
|
190
220
|
end
|
191
221
|
end
|