activerecord 3.2.6 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +611 -6417
- data/MIT-LICENSE +4 -2
- data/README.rdoc +44 -47
- data/examples/performance.rb +79 -71
- data/examples/simple.rb +6 -5
- data/lib/active_record/aggregations.rb +268 -238
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -42
- data/lib/active_record/associations/association.rb +173 -81
- data/lib/active_record/associations/association_scope.rb +124 -92
- data/lib/active_record/associations/belongs_to_association.rb +83 -38
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
- data/lib/active_record/associations/builder/association.rb +113 -32
- data/lib/active_record/associations/builder/belongs_to.rb +105 -60
- data/lib/active_record/associations/builder/collection_association.rb +53 -56
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
- data/lib/active_record/associations/builder/has_many.rb +11 -63
- data/lib/active_record/associations/builder/has_one.rb +47 -45
- data/lib/active_record/associations/builder/singular_association.rb +30 -18
- data/lib/active_record/associations/collection_association.rb +217 -295
- data/lib/active_record/associations/collection_proxy.rb +1074 -77
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +78 -50
- data/lib/active_record/associations/has_many_through_association.rb +99 -61
- data/lib/active_record/associations/has_one_association.rb +75 -30
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
- data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
- data/lib/active_record/associations/join_dependency.rb +208 -164
- data/lib/active_record/associations/preloader/association.rb +93 -87
- data/lib/active_record/associations/preloader/through_association.rb +87 -38
- data/lib/active_record/associations/preloader.rb +134 -110
- data/lib/active_record/associations/singular_association.rb +19 -24
- data/lib/active_record/associations/through_association.rb +61 -27
- data/lib/active_record/associations.rb +1766 -1505
- data/lib/active_record/attribute_assignment.rb +57 -193
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
- data/lib/active_record/attribute_methods/dirty.rb +187 -67
- data/lib/active_record/attribute_methods/primary_key.rb +100 -78
- data/lib/active_record/attribute_methods/query.rb +10 -8
- data/lib/active_record/attribute_methods/read.rb +29 -118
- data/lib/active_record/attribute_methods/serialization.rb +60 -72
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
- data/lib/active_record/attribute_methods/write.rb +36 -44
- data/lib/active_record/attribute_methods.rb +306 -161
- data/lib/active_record/attributes.rb +279 -0
- data/lib/active_record/autosave_association.rb +324 -238
- data/lib/active_record/base.rb +114 -507
- data/lib/active_record/callbacks.rb +147 -83
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +32 -23
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
- data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
- data/lib/active_record/connection_adapters/column.rb +58 -233
- data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
- data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +267 -0
- data/lib/active_record/core.rb +599 -0
- data/lib/active_record/counter_cache.rb +177 -103
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +107 -64
- data/lib/active_record/enum.rb +274 -0
- data/lib/active_record/errors.rb +254 -61
- data/lib/active_record/explain.rb +35 -70
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +18 -8
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +291 -475
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +219 -100
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +175 -17
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +106 -92
- data/lib/active_record/locking/pessimistic.rb +23 -11
- data/lib/active_record/log_subscriber.rb +80 -30
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +235 -56
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/migration.rb +917 -301
- data/lib/active_record/model_schema.rb +351 -175
- data/lib/active_record/nested_attributes.rb +366 -235
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +761 -166
- data/lib/active_record/query_cache.rb +22 -44
- data/lib/active_record/querying.rb +55 -31
- data/lib/active_record/railtie.rb +185 -47
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -4
- data/lib/active_record/railties/controller_runtime.rb +35 -33
- data/lib/active_record/railties/databases.rake +366 -463
- data/lib/active_record/readonly_attributes.rb +4 -6
- data/lib/active_record/reflection.rb +736 -228
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +252 -52
- data/lib/active_record/relation/calculations.rb +340 -270
- data/lib/active_record/relation/delegation.rb +117 -36
- data/lib/active_record/relation/finder_methods.rb +439 -286
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +184 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder.rb +131 -39
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +1163 -221
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +49 -120
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/relation.rb +671 -349
- data/lib/active_record/result.rb +149 -15
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +153 -133
- data/lib/active_record/schema.rb +22 -19
- data/lib/active_record/schema_dumper.rb +178 -112
- data/lib/active_record/schema_migration.rb +60 -0
- data/lib/active_record/scoping/default.rb +107 -98
- data/lib/active_record/scoping/named.rb +130 -115
- data/lib/active_record/scoping.rb +77 -123
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +10 -6
- data/lib/active_record/statement_cache.rb +148 -0
- data/lib/active_record/store.rb +256 -16
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +506 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +93 -39
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +260 -129
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +78 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +35 -18
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +123 -77
- data/lib/active_record/validations.rb +54 -43
- data/lib/active_record/version.rb +7 -7
- data/lib/active_record.rb +97 -49
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/migration.rb +41 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
- data/lib/rails/generators/active_record.rb +10 -16
- metadata +285 -149
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -358
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Tasks # :nodoc:
|
7
|
+
class PostgreSQLDatabaseTasks # :nodoc:
|
8
|
+
DEFAULT_ENCODING = ENV["CHARSET"] || "utf8"
|
9
|
+
ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
|
10
|
+
SQL_COMMENT_BEGIN = "--"
|
11
|
+
|
12
|
+
delegate :connection, :establish_connection, :clear_active_connections!,
|
13
|
+
to: ActiveRecord::Base
|
14
|
+
|
15
|
+
def initialize(configuration)
|
16
|
+
@configuration = configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(master_established = false)
|
20
|
+
establish_master_connection unless master_established
|
21
|
+
connection.create_database configuration["database"],
|
22
|
+
configuration.merge("encoding" => encoding)
|
23
|
+
establish_connection configuration
|
24
|
+
rescue ActiveRecord::StatementInvalid => error
|
25
|
+
if error.cause.is_a?(PG::DuplicateDatabase)
|
26
|
+
raise DatabaseAlreadyExists
|
27
|
+
else
|
28
|
+
raise
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def drop
|
33
|
+
establish_master_connection
|
34
|
+
connection.drop_database configuration["database"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def charset
|
38
|
+
connection.encoding
|
39
|
+
end
|
40
|
+
|
41
|
+
def collation
|
42
|
+
connection.collation
|
43
|
+
end
|
44
|
+
|
45
|
+
def purge
|
46
|
+
clear_active_connections!
|
47
|
+
drop
|
48
|
+
create true
|
49
|
+
end
|
50
|
+
|
51
|
+
def structure_dump(filename, extra_flags)
|
52
|
+
set_psql_env
|
53
|
+
|
54
|
+
search_path = \
|
55
|
+
case ActiveRecord::Base.dump_schemas
|
56
|
+
when :schema_search_path
|
57
|
+
configuration["schema_search_path"]
|
58
|
+
when :all
|
59
|
+
nil
|
60
|
+
when String
|
61
|
+
ActiveRecord::Base.dump_schemas
|
62
|
+
end
|
63
|
+
|
64
|
+
args = ["-s", "-x", "-O", "-f", filename]
|
65
|
+
args.concat(Array(extra_flags)) if extra_flags
|
66
|
+
unless search_path.blank?
|
67
|
+
args += search_path.split(",").map do |part|
|
68
|
+
"--schema=#{part.strip}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
73
|
+
if ignore_tables.any?
|
74
|
+
args += ignore_tables.flat_map { |table| ["-T", table] }
|
75
|
+
end
|
76
|
+
|
77
|
+
args << configuration["database"]
|
78
|
+
run_cmd("pg_dump", args, "dumping")
|
79
|
+
remove_sql_header_comments(filename)
|
80
|
+
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
81
|
+
end
|
82
|
+
|
83
|
+
def structure_load(filename, extra_flags)
|
84
|
+
set_psql_env
|
85
|
+
args = ["-v", ON_ERROR_STOP_1, "-q", "-X", "-f", filename]
|
86
|
+
args.concat(Array(extra_flags)) if extra_flags
|
87
|
+
args << configuration["database"]
|
88
|
+
run_cmd("psql", args, "loading")
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
attr_reader :configuration
|
94
|
+
|
95
|
+
def encoding
|
96
|
+
configuration["encoding"] || DEFAULT_ENCODING
|
97
|
+
end
|
98
|
+
|
99
|
+
def establish_master_connection
|
100
|
+
establish_connection configuration.merge(
|
101
|
+
"database" => "postgres",
|
102
|
+
"schema_search_path" => "public"
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_psql_env
|
107
|
+
ENV["PGHOST"] = configuration["host"] if configuration["host"]
|
108
|
+
ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
|
109
|
+
ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
|
110
|
+
ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
|
111
|
+
end
|
112
|
+
|
113
|
+
def run_cmd(cmd, args, action)
|
114
|
+
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def run_cmd_error(cmd, args, action)
|
118
|
+
msg = +"failed to execute:\n"
|
119
|
+
msg << "#{cmd} #{args.join(' ')}\n\n"
|
120
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
121
|
+
msg
|
122
|
+
end
|
123
|
+
|
124
|
+
def remove_sql_header_comments(filename)
|
125
|
+
removing_comments = true
|
126
|
+
tempfile = Tempfile.open("uncommented_structure.sql")
|
127
|
+
begin
|
128
|
+
File.foreach(filename) do |line|
|
129
|
+
unless removing_comments && (line.start_with?(SQL_COMMENT_BEGIN) || line.blank?)
|
130
|
+
tempfile << line
|
131
|
+
removing_comments = false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
ensure
|
135
|
+
tempfile.close
|
136
|
+
end
|
137
|
+
FileUtils.cp(tempfile.path, filename)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Tasks # :nodoc:
|
5
|
+
class SQLiteDatabaseTasks # :nodoc:
|
6
|
+
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
|
+
|
8
|
+
def initialize(configuration, root = ActiveRecord::Tasks::DatabaseTasks.root)
|
9
|
+
@configuration, @root = configuration, root
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
raise DatabaseAlreadyExists if File.exist?(configuration["database"])
|
14
|
+
|
15
|
+
establish_connection configuration
|
16
|
+
connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def drop
|
20
|
+
require "pathname"
|
21
|
+
path = Pathname.new configuration["database"]
|
22
|
+
file = path.absolute? ? path.to_s : File.join(root, path)
|
23
|
+
|
24
|
+
FileUtils.rm(file)
|
25
|
+
rescue Errno::ENOENT => error
|
26
|
+
raise NoDatabaseError.new(error.message)
|
27
|
+
end
|
28
|
+
|
29
|
+
def purge
|
30
|
+
drop
|
31
|
+
rescue NoDatabaseError
|
32
|
+
ensure
|
33
|
+
create
|
34
|
+
end
|
35
|
+
|
36
|
+
def charset
|
37
|
+
connection.encoding
|
38
|
+
end
|
39
|
+
|
40
|
+
def structure_dump(filename, extra_flags)
|
41
|
+
args = []
|
42
|
+
args.concat(Array(extra_flags)) if extra_flags
|
43
|
+
args << configuration["database"]
|
44
|
+
|
45
|
+
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
46
|
+
if ignore_tables.any?
|
47
|
+
condition = ignore_tables.map { |table| connection.quote(table) }.join(", ")
|
48
|
+
args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
|
49
|
+
else
|
50
|
+
args << ".schema"
|
51
|
+
end
|
52
|
+
run_cmd("sqlite3", args, filename)
|
53
|
+
end
|
54
|
+
|
55
|
+
def structure_load(filename, extra_flags)
|
56
|
+
dbfile = configuration["database"]
|
57
|
+
flags = extra_flags.join(" ") if extra_flags
|
58
|
+
`sqlite3 #{flags} #{dbfile} < "#{filename}"`
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
attr_reader :configuration, :root
|
64
|
+
|
65
|
+
def run_cmd(cmd, args, out)
|
66
|
+
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_cmd_error(cmd, args)
|
70
|
+
msg = +"failed to execute:\n"
|
71
|
+
msg << "#{cmd} #{args.join(' ')}\n\n"
|
72
|
+
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
73
|
+
msg
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/testing/parallelization"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module TestDatabases # :nodoc:
|
7
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
|
8
|
+
create_and_load_schema(i, env_name: Rails.env)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create_and_load_schema(i, env_name:)
|
12
|
+
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
13
|
+
|
14
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
15
|
+
db_config.config["database"] += "-#{i}"
|
16
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
|
17
|
+
end
|
18
|
+
ensure
|
19
|
+
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
20
|
+
ENV["VERBOSE"] = old
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module TestFixtures
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def before_setup # :nodoc:
|
8
|
+
setup_fixtures
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_teardown # :nodoc:
|
13
|
+
super
|
14
|
+
teardown_fixtures
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
class_attribute :fixture_path, instance_writer: false
|
19
|
+
class_attribute :fixture_table_names, default: []
|
20
|
+
class_attribute :fixture_class_names, default: {}
|
21
|
+
class_attribute :use_transactional_tests, default: true
|
22
|
+
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
23
|
+
class_attribute :pre_loaded_fixtures, default: false
|
24
|
+
class_attribute :config, default: ActiveRecord::Base
|
25
|
+
class_attribute :lock_threads, default: true
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
30
|
+
#
|
31
|
+
# Examples:
|
32
|
+
#
|
33
|
+
# set_fixture_class some_fixture: SomeModel,
|
34
|
+
# 'namespaced/fixture' => Another::Model
|
35
|
+
#
|
36
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
37
|
+
def set_fixture_class(class_names = {})
|
38
|
+
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixtures(*fixture_set_names)
|
42
|
+
if fixture_set_names.first == :all
|
43
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
44
|
+
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
|
45
|
+
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
46
|
+
else
|
47
|
+
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
self.fixture_table_names |= fixture_set_names
|
51
|
+
setup_fixture_accessors(fixture_set_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
55
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
56
|
+
methods = Module.new do
|
57
|
+
fixture_set_names.each do |fs_name|
|
58
|
+
fs_name = fs_name.to_s
|
59
|
+
accessor_name = fs_name.tr("/", "_").to_sym
|
60
|
+
|
61
|
+
define_method(accessor_name) do |*fixture_names|
|
62
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
63
|
+
return_single_record = fixture_names.size == 1
|
64
|
+
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
65
|
+
|
66
|
+
@fixture_cache[fs_name] ||= {}
|
67
|
+
|
68
|
+
instances = fixture_names.map do |f_name|
|
69
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
70
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
71
|
+
|
72
|
+
if @loaded_fixtures[fs_name][f_name]
|
73
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
74
|
+
else
|
75
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return_single_record ? instances.first : instances
|
80
|
+
end
|
81
|
+
private accessor_name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
include methods
|
85
|
+
end
|
86
|
+
|
87
|
+
def uses_transaction(*methods)
|
88
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
89
|
+
@uses_transaction.concat methods.map(&:to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
def uses_transaction?(method)
|
93
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
94
|
+
@uses_transaction.include?(method.to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def run_in_transaction?
|
99
|
+
use_transactional_tests &&
|
100
|
+
!self.class.uses_transaction?(method_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
104
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
105
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
106
|
+
end
|
107
|
+
|
108
|
+
@fixture_cache = {}
|
109
|
+
@fixture_connections = []
|
110
|
+
@@already_loaded_fixtures ||= {}
|
111
|
+
@connection_subscriber = nil
|
112
|
+
|
113
|
+
# Load fixtures once and begin transaction.
|
114
|
+
if run_in_transaction?
|
115
|
+
if @@already_loaded_fixtures[self.class]
|
116
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
117
|
+
else
|
118
|
+
@loaded_fixtures = load_fixtures(config)
|
119
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
120
|
+
end
|
121
|
+
|
122
|
+
# Begin transactions for connections already established
|
123
|
+
@fixture_connections = enlist_fixture_connections
|
124
|
+
@fixture_connections.each do |connection|
|
125
|
+
connection.begin_transaction joinable: false, _lazy: false
|
126
|
+
connection.pool.lock_thread = true if lock_threads
|
127
|
+
end
|
128
|
+
|
129
|
+
# When connections are established in the future, begin a transaction too
|
130
|
+
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
131
|
+
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
132
|
+
|
133
|
+
if spec_name
|
134
|
+
begin
|
135
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
136
|
+
rescue ConnectionNotEstablished
|
137
|
+
connection = nil
|
138
|
+
end
|
139
|
+
|
140
|
+
if connection && !@fixture_connections.include?(connection)
|
141
|
+
connection.begin_transaction joinable: false, _lazy: false
|
142
|
+
connection.pool.lock_thread = true if lock_threads
|
143
|
+
@fixture_connections << connection
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Load fixtures for every test.
|
149
|
+
else
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
151
|
+
@@already_loaded_fixtures[self.class] = nil
|
152
|
+
@loaded_fixtures = load_fixtures(config)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Instantiate fixtures for every test if requested.
|
156
|
+
instantiate_fixtures if use_instantiated_fixtures
|
157
|
+
end
|
158
|
+
|
159
|
+
def teardown_fixtures
|
160
|
+
# Rollback changes if a transaction is active.
|
161
|
+
if run_in_transaction?
|
162
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
163
|
+
@fixture_connections.each do |connection|
|
164
|
+
connection.rollback_transaction if connection.transaction_open?
|
165
|
+
connection.pool.lock_thread = false
|
166
|
+
end
|
167
|
+
@fixture_connections.clear
|
168
|
+
else
|
169
|
+
ActiveRecord::FixtureSet.reset_cache
|
170
|
+
end
|
171
|
+
|
172
|
+
ActiveRecord::Base.clear_active_connections!
|
173
|
+
end
|
174
|
+
|
175
|
+
def enlist_fixture_connections
|
176
|
+
setup_shared_connection_pool
|
177
|
+
|
178
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
# Shares the writing connection pool with connections on
|
184
|
+
# other handlers.
|
185
|
+
#
|
186
|
+
# In an application with a primary and replica the test fixtures
|
187
|
+
# need to share a connection pool so that the reading connection
|
188
|
+
# can see data in the open transaction on the writing connection.
|
189
|
+
def setup_shared_connection_pool
|
190
|
+
writing_handler = ActiveRecord::Base.connection_handler
|
191
|
+
|
192
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
193
|
+
if handler != writing_handler
|
194
|
+
handler.connection_pool_list.each do |pool|
|
195
|
+
name = pool.spec.name
|
196
|
+
writing_connection = writing_handler.retrieve_connection_pool(name)
|
197
|
+
handler.send(:owner_to_pool)[name] = writing_connection
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def load_fixtures(config)
|
204
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
205
|
+
Hash[fixtures.map { |f| [f.name, f] }]
|
206
|
+
end
|
207
|
+
|
208
|
+
def instantiate_fixtures
|
209
|
+
if pre_loaded_fixtures
|
210
|
+
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
211
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
212
|
+
else
|
213
|
+
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
214
|
+
@loaded_fixtures.each_value do |fixture_set|
|
215
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def load_instances?
|
221
|
+
use_instantiated_fixtures != :no_instances
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
# = Active Record Timestamp
|
4
|
+
# = Active Record \Timestamp
|
5
5
|
#
|
6
6
|
# Active Record automatically timestamps create and update operations if the
|
7
7
|
# table has fields named <tt>created_at/created_on</tt> or
|
@@ -11,20 +11,31 @@ module ActiveRecord
|
|
11
11
|
#
|
12
12
|
# config.active_record.record_timestamps = false
|
13
13
|
#
|
14
|
-
# Timestamps are in
|
14
|
+
# Timestamps are in UTC by default but you can use the local timezone by setting:
|
15
15
|
#
|
16
|
-
# config.active_record.default_timezone = :
|
16
|
+
# config.active_record.default_timezone = :local
|
17
17
|
#
|
18
18
|
# == Time Zone aware attributes
|
19
19
|
#
|
20
|
-
#
|
20
|
+
# Active Record keeps all the <tt>datetime</tt> and <tt>time</tt> columns
|
21
|
+
# timezone aware. By default, these values are stored in the database as UTC
|
22
|
+
# and converted back to the current <tt>Time.zone</tt> when pulled from the database.
|
21
23
|
#
|
22
|
-
#
|
24
|
+
# This feature can be turned off completely by setting:
|
23
25
|
#
|
24
|
-
#
|
26
|
+
# config.active_record.time_zone_aware_attributes = false
|
25
27
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
+
# You can also specify that only <tt>datetime</tt> columns should be time-zone
|
29
|
+
# aware (while <tt>time</tt> should not) by setting:
|
30
|
+
#
|
31
|
+
# ActiveRecord::Base.time_zone_aware_types = [:datetime]
|
32
|
+
#
|
33
|
+
# You can also add database specific timezone aware types. For example, for PostgreSQL:
|
34
|
+
#
|
35
|
+
# ActiveRecord::Base.time_zone_aware_types += [:tsrange, :tstzrange]
|
36
|
+
#
|
37
|
+
# Finally, you can indicate specific attributes of a model for which time zone
|
38
|
+
# conversion should not applied, for instance by setting:
|
28
39
|
#
|
29
40
|
# class Topic < ActiveRecord::Base
|
30
41
|
# self.skip_time_zone_conversion_for_attributes = [:written_on]
|
@@ -33,23 +44,66 @@ module ActiveRecord
|
|
33
44
|
extend ActiveSupport::Concern
|
34
45
|
|
35
46
|
included do
|
36
|
-
class_attribute :record_timestamps
|
37
|
-
self.record_timestamps = true
|
47
|
+
class_attribute :record_timestamps, default: true
|
38
48
|
end
|
39
49
|
|
40
|
-
def initialize_dup(other)
|
50
|
+
def initialize_dup(other) # :nodoc:
|
51
|
+
super
|
41
52
|
clear_timestamp_attributes
|
42
53
|
end
|
43
54
|
|
55
|
+
module ClassMethods # :nodoc:
|
56
|
+
def touch_attributes_with_time(*names, time: nil)
|
57
|
+
attribute_names = timestamp_attributes_for_update_in_model
|
58
|
+
attribute_names |= names.map(&:to_s)
|
59
|
+
attribute_names.index_with(time || current_time_from_proper_timezone)
|
60
|
+
end
|
61
|
+
|
62
|
+
def timestamp_attributes_for_create_in_model
|
63
|
+
@timestamp_attributes_for_create_in_model ||=
|
64
|
+
(timestamp_attributes_for_create & column_names).freeze
|
65
|
+
end
|
66
|
+
|
67
|
+
def timestamp_attributes_for_update_in_model
|
68
|
+
@timestamp_attributes_for_update_in_model ||=
|
69
|
+
(timestamp_attributes_for_update & column_names).freeze
|
70
|
+
end
|
71
|
+
|
72
|
+
def all_timestamp_attributes_in_model
|
73
|
+
@all_timestamp_attributes_in_model ||=
|
74
|
+
(timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model).freeze
|
75
|
+
end
|
76
|
+
|
77
|
+
def current_time_from_proper_timezone
|
78
|
+
default_timezone == :utc ? Time.now.utc : Time.now
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def timestamp_attributes_for_create
|
83
|
+
["created_at", "created_on"]
|
84
|
+
end
|
85
|
+
|
86
|
+
def timestamp_attributes_for_update
|
87
|
+
["updated_at", "updated_on"]
|
88
|
+
end
|
89
|
+
|
90
|
+
def reload_schema_from_cache
|
91
|
+
@timestamp_attributes_for_create_in_model = nil
|
92
|
+
@timestamp_attributes_for_update_in_model = nil
|
93
|
+
@all_timestamp_attributes_in_model = nil
|
94
|
+
super
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
44
98
|
private
|
45
99
|
|
46
|
-
def
|
47
|
-
if
|
100
|
+
def _create_record
|
101
|
+
if record_timestamps
|
48
102
|
current_time = current_time_from_proper_timezone
|
49
103
|
|
50
|
-
|
51
|
-
if
|
52
|
-
|
104
|
+
all_timestamp_attributes_in_model.each do |column|
|
105
|
+
if !attribute_present?(column)
|
106
|
+
_write_attribute(column, current_time)
|
53
107
|
end
|
54
108
|
end
|
55
109
|
end
|
@@ -57,56 +111,56 @@ module ActiveRecord
|
|
57
111
|
super
|
58
112
|
end
|
59
113
|
|
60
|
-
def
|
61
|
-
if should_record_timestamps?
|
114
|
+
def _update_record
|
115
|
+
if @_touch_record && should_record_timestamps?
|
62
116
|
current_time = current_time_from_proper_timezone
|
63
117
|
|
64
118
|
timestamp_attributes_for_update_in_model.each do |column|
|
65
|
-
|
66
|
-
|
67
|
-
write_attribute(column, current_time)
|
119
|
+
next if will_save_change_to_attribute?(column)
|
120
|
+
_write_attribute(column, current_time)
|
68
121
|
end
|
69
122
|
end
|
123
|
+
|
124
|
+
super
|
125
|
+
end
|
126
|
+
|
127
|
+
def create_or_update(touch: true, **)
|
128
|
+
@_touch_record = touch
|
70
129
|
super
|
71
130
|
end
|
72
131
|
|
73
132
|
def should_record_timestamps?
|
74
|
-
|
133
|
+
record_timestamps && (!partial_writes? || has_changes_to_save?)
|
75
134
|
end
|
76
135
|
|
77
136
|
def timestamp_attributes_for_create_in_model
|
78
|
-
|
137
|
+
self.class.timestamp_attributes_for_create_in_model
|
79
138
|
end
|
80
139
|
|
81
140
|
def timestamp_attributes_for_update_in_model
|
82
|
-
|
141
|
+
self.class.timestamp_attributes_for_update_in_model
|
83
142
|
end
|
84
143
|
|
85
144
|
def all_timestamp_attributes_in_model
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
def timestamp_attributes_for_update #:nodoc:
|
90
|
-
[:updated_at, :updated_on]
|
91
|
-
end
|
92
|
-
|
93
|
-
def timestamp_attributes_for_create #:nodoc:
|
94
|
-
[:created_at, :created_on]
|
145
|
+
self.class.all_timestamp_attributes_in_model
|
95
146
|
end
|
96
147
|
|
97
|
-
def
|
98
|
-
|
148
|
+
def current_time_from_proper_timezone
|
149
|
+
self.class.current_time_from_proper_timezone
|
99
150
|
end
|
100
151
|
|
101
|
-
def
|
102
|
-
|
152
|
+
def max_updated_column_timestamp
|
153
|
+
timestamp_attributes_for_update_in_model
|
154
|
+
.map { |attr| self[attr]&.to_time }
|
155
|
+
.compact
|
156
|
+
.max
|
103
157
|
end
|
104
158
|
|
105
159
|
# Clear attributes and changed_attributes
|
106
160
|
def clear_timestamp_attributes
|
107
161
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
108
162
|
self[attribute_name] = nil
|
109
|
-
|
163
|
+
clear_attribute_changes([attribute_name])
|
110
164
|
end
|
111
165
|
end
|
112
166
|
end
|