activerecord 4.2.11.1 → 6.0.3.5
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 +721 -1522
- data/MIT-LICENSE +4 -2
- data/README.rdoc +14 -13
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +20 -13
- data/lib/active_record/associations/alias_tracker.rb +29 -36
- data/lib/active_record/associations/association.rb +128 -57
- 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 +50 -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 +136 -288
- data/lib/active_record/associations/collection_proxy.rb +241 -147
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -98
- 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/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/join_dependency.rb +149 -166
- 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/preloader.rb +90 -93
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/attribute_assignment.rb +57 -185
- data/lib/active_record/attribute_decorators.rb +39 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- data/lib/active_record/attribute_methods/primary_key.rb +90 -84
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -77
- data/lib/active_record/attribute_methods/serialization.rb +40 -21
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +57 -37
- data/lib/active_record/attribute_methods/write.rb +32 -55
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attributes.rb +213 -82
- data/lib/active_record/autosave_association.rb +97 -41
- data/lib/active_record/base.rb +57 -45
- data/lib/active_record/callbacks.rb +101 -76
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +804 -297
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +240 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
- 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 -47
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +371 -242
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +694 -256
- data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +473 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +507 -639
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
- 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 +196 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -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 -181
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -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 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +51 -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 +9 -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/oid.rb +23 -25
- 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 +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -296
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -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 +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -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 +299 -349
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_handling.rb +167 -41
- data/lib/active_record/core.rb +252 -230
- data/lib/active_record/counter_cache.rb +70 -49
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -53
- data/lib/active_record/explain.rb +22 -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 +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +227 -501
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +158 -115
- 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 +86 -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/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +166 -91
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +623 -305
- data/lib/active_record/model_schema.rb +313 -112
- data/lib/active_record/nested_attributes.rb +263 -223
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +557 -126
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +44 -30
- 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 +331 -185
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +430 -281
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +206 -55
- data/lib/active_record/relation/calculations.rb +268 -254
- data/lib/active_record/relation/delegation.rb +75 -84
- data/lib/active_record/relation/finder_methods.rb +285 -241
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +78 -88
- 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/predicate_builder.rb +110 -119
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +603 -397
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -14
- data/lib/active_record/relation/where_clause.rb +189 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/relation.rb +530 -341
- data/lib/active_record/result.rb +79 -43
- 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/default.rb +98 -83
- data/lib/active_record/scoping/named.rb +86 -33
- data/lib/active_record/scoping.rb +45 -27
- 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 +90 -0
- data/lib/active_record/tasks/database_tasks.rb +307 -100
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +80 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +86 -41
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +223 -157
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -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 -4
- 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 +23 -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 +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +77 -23
- 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 +12 -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/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- 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/migration.rb +30 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -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
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +168 -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/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- 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/integer.rb +0 -11
- 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
data/lib/active_record/store.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
# Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column.
|
@@ -9,39 +11,66 @@ module ActiveRecord
|
|
9
11
|
# of the model. This is very helpful for easily exposing store keys to a form or elsewhere that's
|
10
12
|
# already built around just accessing attributes on the model.
|
11
13
|
#
|
14
|
+
# Every accessor comes with dirty tracking methods (+key_changed?+, +key_was+ and +key_change+) and
|
15
|
+
# methods to access the changes made during the last save (+saved_change_to_key?+, +saved_change_to_key+ and
|
16
|
+
# +key_before_last_save+).
|
17
|
+
#
|
18
|
+
# NOTE: There is no +key_will_change!+ method for accessors, use +store_will_change!+ instead.
|
19
|
+
#
|
12
20
|
# Make sure that you declare the database column used for the serialized store as a text, so there's
|
13
21
|
# plenty of room.
|
14
22
|
#
|
15
23
|
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
|
16
24
|
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
|
17
25
|
#
|
18
|
-
# NOTE
|
19
|
-
#
|
26
|
+
# NOTE: If you are using structured database data types (eg. PostgreSQL +hstore+/+json+, or MySQL 5.7+
|
27
|
+
# +json+) there is no need for the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
28
|
+
# Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
|
20
29
|
# the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
|
21
30
|
# using a symbol.
|
22
31
|
#
|
32
|
+
# NOTE: The default validations with the exception of +uniqueness+ will work.
|
33
|
+
# For example, if you want to check for +uniqueness+ with +hstore+ you will
|
34
|
+
# need to use a custom validation to handle it.
|
35
|
+
#
|
23
36
|
# Examples:
|
24
37
|
#
|
25
38
|
# class User < ActiveRecord::Base
|
26
39
|
# store :settings, accessors: [ :color, :homepage ], coder: JSON
|
40
|
+
# store :parent, accessors: [ :name ], coder: JSON, prefix: true
|
41
|
+
# store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
|
42
|
+
# store :settings, accessors: [ :two_factor_auth ], suffix: true
|
43
|
+
# store :settings, accessors: [ :login_retry ], suffix: :config
|
27
44
|
# end
|
28
45
|
#
|
29
|
-
# u = User.new(color: 'black', homepage: '37signals.com')
|
46
|
+
# u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
|
30
47
|
# u.color # Accessor stored attribute
|
48
|
+
# u.parent_name # Accessor stored attribute with prefix
|
49
|
+
# u.partner_name # Accessor stored attribute with custom prefix
|
50
|
+
# u.two_factor_auth_settings # Accessor stored attribute with suffix
|
51
|
+
# u.login_retry_config # Accessor stored attribute with custom suffix
|
31
52
|
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
|
32
53
|
#
|
33
54
|
# # There is no difference between strings and symbols for accessing custom attributes
|
34
55
|
# u.settings[:country] # => 'Denmark'
|
35
56
|
# u.settings['country'] # => 'Denmark'
|
36
57
|
#
|
58
|
+
# # Dirty tracking
|
59
|
+
# u.color = 'green'
|
60
|
+
# u.color_changed? # => true
|
61
|
+
# u.color_was # => 'black'
|
62
|
+
# u.color_change # => ['black', 'red']
|
63
|
+
#
|
37
64
|
# # Add additional accessors to an existing store through store_accessor
|
38
65
|
# class SuperUser < User
|
39
66
|
# store_accessor :settings, :privileges, :servants
|
67
|
+
# store_accessor :parent, :birthday, prefix: true
|
68
|
+
# store_accessor :settings, :secret_question, suffix: :config
|
40
69
|
# end
|
41
70
|
#
|
42
|
-
# The stored attribute names can be retrieved using
|
71
|
+
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
43
72
|
#
|
44
|
-
# User.stored_attributes[:settings] # [:color, :homepage]
|
73
|
+
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
|
45
74
|
#
|
46
75
|
# == Overwriting default accessors
|
47
76
|
#
|
@@ -73,22 +102,79 @@ module ActiveRecord
|
|
73
102
|
|
74
103
|
module ClassMethods
|
75
104
|
def store(store_attribute, options = {})
|
76
|
-
serialize store_attribute, IndifferentCoder.new(options[:coder])
|
77
|
-
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
|
105
|
+
serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
|
106
|
+
store_accessor(store_attribute, options[:accessors], **options.slice(:prefix, :suffix)) if options.has_key? :accessors
|
78
107
|
end
|
79
108
|
|
80
|
-
def store_accessor(store_attribute, *keys)
|
109
|
+
def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
|
81
110
|
keys = keys.flatten
|
82
111
|
|
112
|
+
accessor_prefix =
|
113
|
+
case prefix
|
114
|
+
when String, Symbol
|
115
|
+
"#{prefix}_"
|
116
|
+
when TrueClass
|
117
|
+
"#{store_attribute}_"
|
118
|
+
else
|
119
|
+
""
|
120
|
+
end
|
121
|
+
accessor_suffix =
|
122
|
+
case suffix
|
123
|
+
when String, Symbol
|
124
|
+
"_#{suffix}"
|
125
|
+
when TrueClass
|
126
|
+
"_#{store_attribute}"
|
127
|
+
else
|
128
|
+
""
|
129
|
+
end
|
130
|
+
|
83
131
|
_store_accessors_module.module_eval do
|
84
132
|
keys.each do |key|
|
85
|
-
|
133
|
+
accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}"
|
134
|
+
|
135
|
+
define_method("#{accessor_key}=") do |value|
|
86
136
|
write_store_attribute(store_attribute, key, value)
|
87
137
|
end
|
88
138
|
|
89
|
-
define_method(
|
139
|
+
define_method(accessor_key) do
|
90
140
|
read_store_attribute(store_attribute, key)
|
91
141
|
end
|
142
|
+
|
143
|
+
define_method("#{accessor_key}_changed?") do
|
144
|
+
return false unless attribute_changed?(store_attribute)
|
145
|
+
prev_store, new_store = changes[store_attribute]
|
146
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
147
|
+
end
|
148
|
+
|
149
|
+
define_method("#{accessor_key}_change") do
|
150
|
+
return unless attribute_changed?(store_attribute)
|
151
|
+
prev_store, new_store = changes[store_attribute]
|
152
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
153
|
+
end
|
154
|
+
|
155
|
+
define_method("#{accessor_key}_was") do
|
156
|
+
return unless attribute_changed?(store_attribute)
|
157
|
+
prev_store, _new_store = changes[store_attribute]
|
158
|
+
prev_store&.dig(key)
|
159
|
+
end
|
160
|
+
|
161
|
+
define_method("saved_change_to_#{accessor_key}?") do
|
162
|
+
return false unless saved_change_to_attribute?(store_attribute)
|
163
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
164
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
165
|
+
end
|
166
|
+
|
167
|
+
define_method("saved_change_to_#{accessor_key}") do
|
168
|
+
return unless saved_change_to_attribute?(store_attribute)
|
169
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
170
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
171
|
+
end
|
172
|
+
|
173
|
+
define_method("#{accessor_key}_before_last_save") do
|
174
|
+
return unless saved_change_to_attribute?(store_attribute)
|
175
|
+
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
176
|
+
prev_store&.dig(key)
|
177
|
+
end
|
92
178
|
end
|
93
179
|
end
|
94
180
|
|
@@ -109,27 +195,26 @@ module ActiveRecord
|
|
109
195
|
|
110
196
|
def stored_attributes
|
111
197
|
parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {}
|
112
|
-
if
|
113
|
-
parent.merge!(
|
198
|
+
if local_stored_attributes
|
199
|
+
parent.merge!(local_stored_attributes) { |k, a, b| a | b }
|
114
200
|
end
|
115
201
|
parent
|
116
202
|
end
|
117
203
|
end
|
118
204
|
|
119
|
-
|
120
|
-
def read_store_attribute(store_attribute, key)
|
205
|
+
private
|
206
|
+
def read_store_attribute(store_attribute, key) # :doc:
|
121
207
|
accessor = store_accessor_for(store_attribute)
|
122
208
|
accessor.read(self, store_attribute, key)
|
123
209
|
end
|
124
210
|
|
125
|
-
def write_store_attribute(store_attribute, key, value)
|
211
|
+
def write_store_attribute(store_attribute, key, value) # :doc:
|
126
212
|
accessor = store_accessor_for(store_attribute)
|
127
213
|
accessor.write(self, store_attribute, key, value)
|
128
214
|
end
|
129
215
|
|
130
|
-
private
|
131
216
|
def store_accessor_for(store_attribute)
|
132
|
-
type_for_attribute(store_attribute
|
217
|
+
type_for_attribute(store_attribute).accessor
|
133
218
|
end
|
134
219
|
|
135
220
|
class HashAccessor # :nodoc:
|
@@ -172,34 +257,34 @@ module ActiveRecord
|
|
172
257
|
end
|
173
258
|
end
|
174
259
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
260
|
+
class IndifferentCoder # :nodoc:
|
261
|
+
def initialize(attr_name, coder_or_class_name)
|
262
|
+
@coder =
|
263
|
+
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
|
264
|
+
coder_or_class_name
|
265
|
+
else
|
266
|
+
ActiveRecord::Coders::YAMLColumn.new(attr_name, coder_or_class_name || Object)
|
267
|
+
end
|
268
|
+
end
|
184
269
|
|
185
|
-
|
186
|
-
|
187
|
-
|
270
|
+
def dump(obj)
|
271
|
+
@coder.dump self.class.as_indifferent_hash(obj)
|
272
|
+
end
|
188
273
|
|
189
|
-
|
190
|
-
|
191
|
-
|
274
|
+
def load(yaml)
|
275
|
+
self.class.as_indifferent_hash(@coder.load(yaml || ""))
|
276
|
+
end
|
192
277
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
278
|
+
def self.as_indifferent_hash(obj)
|
279
|
+
case obj
|
280
|
+
when ActiveSupport::HashWithIndifferentAccess
|
281
|
+
obj
|
282
|
+
when Hash
|
283
|
+
obj.with_indifferent_access
|
284
|
+
else
|
285
|
+
ActiveSupport::HashWithIndifferentAccess.new
|
286
|
+
end
|
201
287
|
end
|
202
288
|
end
|
203
|
-
end
|
204
289
|
end
|
205
290
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# ActiveRecord::Suppressor prevents the receiver from being saved during
|
5
|
+
# a given block.
|
6
|
+
#
|
7
|
+
# For example, here's a pattern of creating notifications when new comments
|
8
|
+
# are posted. (The notification may in turn trigger an email, a push
|
9
|
+
# notification, or just appear in the UI somewhere):
|
10
|
+
#
|
11
|
+
# class Comment < ActiveRecord::Base
|
12
|
+
# belongs_to :commentable, polymorphic: true
|
13
|
+
# after_create -> { Notification.create! comment: self,
|
14
|
+
# recipients: commentable.recipients }
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# That's what you want the bulk of the time. New comment creates a new
|
18
|
+
# Notification. But there may well be off cases, like copying a commentable
|
19
|
+
# and its comments, where you don't want that. So you'd have a concern
|
20
|
+
# something like this:
|
21
|
+
#
|
22
|
+
# module Copyable
|
23
|
+
# def copy_to(destination)
|
24
|
+
# Notification.suppress do
|
25
|
+
# # Copy logic that creates new comments that we do not want
|
26
|
+
# # triggering notifications.
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
module Suppressor
|
31
|
+
extend ActiveSupport::Concern
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def suppress(&block)
|
35
|
+
previous_state = SuppressorRegistry.suppressed[name]
|
36
|
+
SuppressorRegistry.suppressed[name] = true
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
SuppressorRegistry.suppressed[name] = previous_state
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def save(*, **) # :nodoc:
|
44
|
+
SuppressorRegistry.suppressed[self.class.name] ? true : super
|
45
|
+
end
|
46
|
+
|
47
|
+
def save!(*, **) # :nodoc:
|
48
|
+
SuppressorRegistry.suppressed[self.class.name] ? true : super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class SuppressorRegistry # :nodoc:
|
53
|
+
extend ActiveSupport::PerThreadRegistry
|
54
|
+
|
55
|
+
attr_reader :suppressed
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@suppressed = {}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class TableMetadata # :nodoc:
|
5
|
+
delegate :foreign_type, :foreign_key, :join_primary_key, :join_foreign_key, to: :association, prefix: true
|
6
|
+
|
7
|
+
def initialize(klass, arel_table, association = nil, types = klass)
|
8
|
+
@klass = klass
|
9
|
+
@types = types
|
10
|
+
@arel_table = arel_table
|
11
|
+
@association = association
|
12
|
+
end
|
13
|
+
|
14
|
+
def resolve_column_aliases(hash)
|
15
|
+
new_hash = hash.dup
|
16
|
+
hash.each_key do |key|
|
17
|
+
if key.is_a?(Symbol) && new_key = klass.attribute_aliases[key.to_s]
|
18
|
+
new_hash[new_key] = new_hash.delete(key)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
new_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def arel_attribute(column_name)
|
25
|
+
if klass
|
26
|
+
klass.arel_attribute(column_name, arel_table)
|
27
|
+
else
|
28
|
+
arel_table[column_name]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def type(column_name)
|
33
|
+
types.type_for_attribute(column_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_column?(column_name)
|
37
|
+
klass && klass.columns_hash.key?(column_name.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def associated_with?(association_name)
|
41
|
+
klass && klass._reflect_on_association(association_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def associated_table(table_name)
|
45
|
+
association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.to_s.singularize)
|
46
|
+
|
47
|
+
if !association && table_name == arel_table.name
|
48
|
+
self
|
49
|
+
elsif association && !association.polymorphic?
|
50
|
+
association_klass = association.klass
|
51
|
+
arel_table = association_klass.arel_table.alias(table_name)
|
52
|
+
TableMetadata.new(association_klass, arel_table, association)
|
53
|
+
else
|
54
|
+
type_caster = TypeCaster::Connection.new(klass, table_name)
|
55
|
+
arel_table = Arel::Table.new(table_name, type_caster: type_caster)
|
56
|
+
TableMetadata.new(nil, arel_table, association, type_caster)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def associated_predicate_builder(table_name)
|
61
|
+
associated_table(table_name).predicate_builder
|
62
|
+
end
|
63
|
+
|
64
|
+
def polymorphic_association?
|
65
|
+
association && association.polymorphic?
|
66
|
+
end
|
67
|
+
|
68
|
+
def aggregated_with?(aggregation_name)
|
69
|
+
klass && reflect_on_aggregation(aggregation_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def reflect_on_aggregation(aggregation_name)
|
73
|
+
klass.reflect_on_aggregation(aggregation_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
def predicate_builder
|
78
|
+
if klass
|
79
|
+
predicate_builder = klass.predicate_builder.dup
|
80
|
+
predicate_builder.instance_variable_set(:@table, self)
|
81
|
+
predicate_builder
|
82
|
+
else
|
83
|
+
PredicateBuilder.new(self)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
attr_reader :klass, :types, :arel_table, :association
|
89
|
+
end
|
90
|
+
end
|