activerecord 4.2.0 → 6.1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1221 -796
- data/MIT-LICENSE +4 -2
- data/README.rdoc +15 -14
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +267 -249
- data/lib/active_record/association_relation.rb +45 -7
- data/lib/active_record/associations/alias_tracker.rb +40 -43
- data/lib/active_record/associations/association.rb +172 -67
- data/lib/active_record/associations/association_scope.rb +105 -129
- data/lib/active_record/associations/belongs_to_association.rb +85 -59
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +57 -43
- data/lib/active_record/associations/builder/belongs_to.rb +74 -57
- data/lib/active_record/associations/builder/collection_association.rb +15 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
- data/lib/active_record/associations/builder/has_many.rb +13 -5
- data/lib/active_record/associations/builder/has_one.rb +44 -6
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +168 -279
- data/lib/active_record/associations/collection_proxy.rb +263 -155
- data/lib/active_record/associations/foreign_association.rb +33 -0
- data/lib/active_record/associations/has_many_association.rb +57 -84
- data/lib/active_record/associations/has_many_through_association.rb +70 -82
- data/lib/active_record/associations/has_one_association.rb +74 -47
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
- 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 +175 -164
- data/lib/active_record/associations/preloader/association.rb +107 -112
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +99 -96
- data/lib/active_record/associations/singular_association.rb +18 -45
- data/lib/active_record/associations/through_association.rb +49 -24
- data/lib/active_record/associations.rb +1845 -1597
- data/lib/active_record/attribute_assignment.rb +59 -185
- data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
- data/lib/active_record/attribute_methods/dirty.rb +168 -138
- data/lib/active_record/attribute_methods/primary_key.rb +93 -83
- data/lib/active_record/attribute_methods/query.rb +8 -10
- data/lib/active_record/attribute_methods/read.rb +19 -79
- data/lib/active_record/attribute_methods/serialization.rb +49 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
- data/lib/active_record/attribute_methods/write.rb +25 -56
- data/lib/active_record/attribute_methods.rb +153 -162
- data/lib/active_record/attributes.rb +234 -70
- data/lib/active_record/autosave_association.rb +157 -69
- data/lib/active_record/base.rb +49 -50
- data/lib/active_record/callbacks.rb +234 -79
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +46 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
- data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
- data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
- data/lib/active_record/connection_adapters/column.rb +67 -40
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -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 +96 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
- 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 +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
- 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/interval.rb +49 -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/macaddr.rb +25 -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 +70 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- 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 +25 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -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 +499 -293
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
- data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -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 +21 -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 +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +314 -41
- data/lib/active_record/core.rb +488 -243
- data/lib/active_record/counter_cache.rb +71 -50
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +273 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +212 -94
- data/lib/active_record/errors.rb +225 -54
- data/lib/active_record/explain.rb +27 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +33 -14
- data/lib/active_record/fixture_set/model_metadata.rb +32 -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 +273 -496
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +175 -110
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +121 -29
- data/lib/active_record/internal_metadata.rb +64 -0
- data/lib/active_record/legacy_yaml_adapter.rb +52 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +103 -95
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +93 -31
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +185 -90
- data/lib/active_record/migration/compatibility.rb +298 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +685 -309
- data/lib/active_record/model_schema.rb +420 -113
- data/lib/active_record/nested_attributes.rb +265 -216
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +574 -135
- data/lib/active_record/query_cache.rb +29 -23
- data/lib/active_record/querying.rb +50 -31
- data/lib/active_record/railtie.rb +175 -54
- data/lib/active_record/railties/console_sandbox.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +533 -216
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +485 -310
- data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
- data/lib/active_record/relation/batches.rb +217 -59
- data/lib/active_record/relation/calculations.rb +326 -244
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +318 -256
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +99 -84
- data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -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 +57 -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 +139 -96
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +757 -409
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +23 -21
- data/lib/active_record/relation/where_clause.rb +239 -0
- data/lib/active_record/relation.rb +554 -342
- data/lib/active_record/result.rb +91 -47
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +134 -122
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +141 -92
- data/lib/active_record/schema_migration.rb +24 -26
- data/lib/active_record/scoping/default.rb +96 -82
- data/lib/active_record/scoping/named.rb +78 -36
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +48 -0
- data/lib/active_record/serialization.rb +8 -6
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +89 -36
- data/lib/active_record/store.rb +133 -43
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +81 -0
- data/lib/active_record/tasks/database_tasks.rb +366 -129
- data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +291 -0
- data/lib/active_record/timestamp.rb +86 -43
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +181 -152
- 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 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
- 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 +33 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +21 -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 +84 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -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/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +65 -48
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +44 -28
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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 +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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 +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -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 +43 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
- data/lib/rails/generators/active_record/migration.rb +35 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +175 -65
- 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 -149
- data/lib/active_record/attribute_decorators.rb +0 -66
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,140 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module DynamicMatchers #:nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
private
|
6
|
+
def respond_to_missing?(name, _)
|
7
|
+
if self == Base
|
8
|
+
super
|
9
|
+
else
|
10
|
+
match = Method.match(self, name)
|
11
|
+
match && match.valid? || super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *arguments, &block)
|
12
16
|
match = Method.match(self, name)
|
13
|
-
|
17
|
+
|
18
|
+
if match && match.valid?
|
19
|
+
match.define
|
20
|
+
send(name, *arguments, &block)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
14
24
|
end
|
15
|
-
end
|
16
25
|
|
17
|
-
|
26
|
+
class Method
|
27
|
+
@matchers = []
|
18
28
|
|
19
|
-
|
20
|
-
|
29
|
+
class << self
|
30
|
+
attr_reader :matchers
|
21
31
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
32
|
+
def match(model, name)
|
33
|
+
klass = matchers.find { |k| k.pattern.match?(name) }
|
34
|
+
klass.new(model, name) if klass
|
35
|
+
end
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
def pattern
|
38
|
+
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
39
|
+
end
|
32
40
|
|
33
|
-
|
34
|
-
|
41
|
+
def prefix
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
45
|
+
def suffix
|
46
|
+
""
|
47
|
+
end
|
39
48
|
end
|
40
49
|
|
41
|
-
|
42
|
-
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
43
|
-
end
|
50
|
+
attr_reader :model, :name, :attribute_names
|
44
51
|
|
45
|
-
def
|
46
|
-
|
52
|
+
def initialize(model, method_name)
|
53
|
+
@model = model
|
54
|
+
@name = method_name.to_s
|
55
|
+
@attribute_names = @name.match(self.class.pattern)[1].split("_and_")
|
56
|
+
@attribute_names.map! { |name| @model.attribute_aliases[name] || name }
|
47
57
|
end
|
48
58
|
|
49
|
-
def
|
50
|
-
|
59
|
+
def valid?
|
60
|
+
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
51
61
|
end
|
52
|
-
end
|
53
62
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def valid?
|
64
|
-
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
65
|
-
end
|
63
|
+
def define
|
64
|
+
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
65
|
+
def self.#{name}(#{signature})
|
66
|
+
#{body}
|
67
|
+
end
|
68
|
+
CODE
|
69
|
+
end
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
#{body}
|
71
|
+
private
|
72
|
+
def body
|
73
|
+
"#{finder}(#{attributes_hash})"
|
71
74
|
end
|
72
|
-
CODE
|
73
|
-
end
|
74
|
-
|
75
|
-
def body
|
76
|
-
raise NotImplementedError
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
module Finder
|
81
|
-
# Extended in activerecord-deprecated_finders
|
82
|
-
def body
|
83
|
-
result
|
84
|
-
end
|
85
75
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# The parameters in the signature may have reserved Ruby words, in order
|
92
|
-
# to prevent errors, we start each param name with `_`.
|
93
|
-
#
|
94
|
-
# Extended in activerecord-deprecated_finders
|
95
|
-
def signature
|
96
|
-
attribute_names.map { |name| "_#{name}" }.join(', ')
|
97
|
-
end
|
76
|
+
# The parameters in the signature may have reserved Ruby words, in order
|
77
|
+
# to prevent errors, we start each param name with `_`.
|
78
|
+
def signature
|
79
|
+
attribute_names.map { |name| "_#{name}" }.join(", ")
|
80
|
+
end
|
98
81
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
82
|
+
# Given that the parameters starts with `_`, the finder needs to use the
|
83
|
+
# same parameter name.
|
84
|
+
def attributes_hash
|
85
|
+
"{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(",") + "}"
|
86
|
+
end
|
104
87
|
|
105
|
-
|
106
|
-
|
88
|
+
def finder
|
89
|
+
raise NotImplementedError
|
90
|
+
end
|
107
91
|
end
|
108
|
-
end
|
109
92
|
|
110
|
-
|
111
|
-
|
112
|
-
include Finder
|
93
|
+
class FindBy < Method
|
94
|
+
Method.matchers << self
|
113
95
|
|
114
|
-
|
115
|
-
|
116
|
-
|
96
|
+
def self.prefix
|
97
|
+
"find_by"
|
98
|
+
end
|
117
99
|
|
118
|
-
|
119
|
-
|
100
|
+
def finder
|
101
|
+
"find_by"
|
102
|
+
end
|
120
103
|
end
|
121
|
-
end
|
122
104
|
|
123
|
-
|
124
|
-
|
125
|
-
include Finder
|
105
|
+
class FindByBang < Method
|
106
|
+
Method.matchers << self
|
126
107
|
|
127
|
-
|
128
|
-
|
129
|
-
|
108
|
+
def self.prefix
|
109
|
+
"find_by"
|
110
|
+
end
|
130
111
|
|
131
|
-
|
132
|
-
|
133
|
-
|
112
|
+
def self.suffix
|
113
|
+
"!"
|
114
|
+
end
|
134
115
|
|
135
|
-
|
136
|
-
|
116
|
+
def finder
|
117
|
+
"find_by!"
|
118
|
+
end
|
137
119
|
end
|
138
|
-
end
|
139
120
|
end
|
140
121
|
end
|
data/lib/active_record/enum.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/deep_dup"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
# Declare an enum attribute where the values map to integers in the database,
|
@@ -18,10 +20,9 @@ module ActiveRecord
|
|
18
20
|
# conversation.archived? # => true
|
19
21
|
# conversation.status # => "archived"
|
20
22
|
#
|
21
|
-
# # conversation.
|
23
|
+
# # conversation.status = 1
|
22
24
|
# conversation.status = "archived"
|
23
25
|
#
|
24
|
-
# # conversation.update! status: nil
|
25
26
|
# conversation.status = nil
|
26
27
|
# conversation.status.nil? # => true
|
27
28
|
# conversation.status # => nil
|
@@ -30,24 +31,39 @@ module ActiveRecord
|
|
30
31
|
# as well. With the above example:
|
31
32
|
#
|
32
33
|
# Conversation.active
|
34
|
+
# Conversation.not_active
|
33
35
|
# Conversation.archived
|
36
|
+
# Conversation.not_archived
|
37
|
+
#
|
38
|
+
# Of course, you can also query them directly if the scopes don't fit your
|
39
|
+
# needs:
|
34
40
|
#
|
35
|
-
#
|
41
|
+
# Conversation.where(status: [:active, :archived])
|
42
|
+
# Conversation.where.not(status: :active)
|
36
43
|
#
|
37
|
-
#
|
38
|
-
#
|
44
|
+
# Defining scopes can be disabled by setting +:_scopes+ to +false+.
|
45
|
+
#
|
46
|
+
# class Conversation < ActiveRecord::Base
|
47
|
+
# enum status: [ :active, :archived ], _scopes: false
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# You can set the default enum value by setting +:_default+, like:
|
51
|
+
#
|
52
|
+
# class Conversation < ActiveRecord::Base
|
53
|
+
# enum status: [ :active, :archived ], _default: "active"
|
39
54
|
# end
|
40
55
|
#
|
41
|
-
#
|
56
|
+
# conversation = Conversation.new
|
57
|
+
# conversation.status # => "active"
|
42
58
|
#
|
43
59
|
# Finally, it's also possible to explicitly map the relation between attribute and
|
44
|
-
# database integer with a
|
60
|
+
# database integer with a hash:
|
45
61
|
#
|
46
62
|
# class Conversation < ActiveRecord::Base
|
47
63
|
# enum status: { active: 0, archived: 1 }
|
48
64
|
# end
|
49
65
|
#
|
50
|
-
# Note that when an
|
66
|
+
# Note that when an array is used, the implicit mapping from the values to database
|
51
67
|
# integers is derived from the order the values appear in the array. In the example,
|
52
68
|
# <tt>:active</tt> is mapped to +0+ as it's the first element, and <tt>:archived</tt>
|
53
69
|
# is mapped to +1+. In general, the +i+-th element is mapped to <tt>i-1</tt> in the
|
@@ -55,23 +71,42 @@ module ActiveRecord
|
|
55
71
|
#
|
56
72
|
# Therefore, once a value is added to the enum array, its position in the array must
|
57
73
|
# be maintained, and new values should only be added to the end of the array. To
|
58
|
-
# remove unused values, the explicit
|
74
|
+
# remove unused values, the explicit hash syntax should be used.
|
59
75
|
#
|
60
76
|
# In rare circumstances you might need to access the mapping directly.
|
61
77
|
# The mappings are exposed through a class method with the pluralized attribute
|
62
|
-
# name
|
78
|
+
# name, which return the mapping in a +HashWithIndifferentAccess+:
|
63
79
|
#
|
64
|
-
# Conversation.statuses
|
80
|
+
# Conversation.statuses[:active] # => 0
|
81
|
+
# Conversation.statuses["archived"] # => 1
|
65
82
|
#
|
66
|
-
# Use that class method when you need to know the ordinal value of an enum
|
83
|
+
# Use that class method when you need to know the ordinal value of an enum.
|
84
|
+
# For example, you can use that when manually building SQL strings:
|
67
85
|
#
|
68
86
|
# Conversation.where("status <> ?", Conversation.statuses[:archived])
|
69
87
|
#
|
70
|
-
#
|
88
|
+
# You can use the +:_prefix+ or +:_suffix+ options when you need to define
|
89
|
+
# multiple enums with same values. If the passed value is +true+, the methods
|
90
|
+
# are prefixed/suffixed with the name of the enum. It is also possible to
|
91
|
+
# supply a custom value:
|
92
|
+
#
|
93
|
+
# class Conversation < ActiveRecord::Base
|
94
|
+
# enum status: [:active, :archived], _suffix: true
|
95
|
+
# enum comments_status: [:active, :inactive], _prefix: :comments
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# With the above example, the bang and predicate methods along with the
|
99
|
+
# associated scopes are now prefixed and/or suffixed accordingly:
|
100
|
+
#
|
101
|
+
# conversation.active_status!
|
102
|
+
# conversation.archived_status? # => false
|
103
|
+
#
|
104
|
+
# conversation.comments_inactive!
|
105
|
+
# conversation.comments_active? # => false
|
106
|
+
|
71
107
|
module Enum
|
72
108
|
def self.extended(base) # :nodoc:
|
73
|
-
base.class_attribute(:defined_enums)
|
74
|
-
base.defined_enums = {}
|
109
|
+
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
75
110
|
end
|
76
111
|
|
77
112
|
def inherited(base) # :nodoc:
|
@@ -79,119 +114,202 @@ module ActiveRecord
|
|
79
114
|
super
|
80
115
|
end
|
81
116
|
|
117
|
+
class EnumType < Type::Value # :nodoc:
|
118
|
+
delegate :type, to: :subtype
|
119
|
+
|
120
|
+
def initialize(name, mapping, subtype)
|
121
|
+
@name = name
|
122
|
+
@mapping = mapping
|
123
|
+
@subtype = subtype
|
124
|
+
end
|
125
|
+
|
126
|
+
def cast(value)
|
127
|
+
if mapping.has_key?(value)
|
128
|
+
value.to_s
|
129
|
+
elsif mapping.has_value?(value)
|
130
|
+
mapping.key(value)
|
131
|
+
elsif value.blank?
|
132
|
+
nil
|
133
|
+
else
|
134
|
+
assert_valid_value(value)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def deserialize(value)
|
139
|
+
mapping.key(subtype.deserialize(value))
|
140
|
+
end
|
141
|
+
|
142
|
+
def serialize(value)
|
143
|
+
mapping.fetch(value, value)
|
144
|
+
end
|
145
|
+
|
146
|
+
def assert_valid_value(value)
|
147
|
+
unless value.blank? || mapping.has_key?(value) || mapping.has_value?(value)
|
148
|
+
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
attr_reader :subtype
|
153
|
+
|
154
|
+
private
|
155
|
+
attr_reader :name, :mapping
|
156
|
+
end
|
157
|
+
|
82
158
|
def enum(definitions)
|
83
|
-
|
159
|
+
enum_prefix = definitions.delete(:_prefix)
|
160
|
+
enum_suffix = definitions.delete(:_suffix)
|
161
|
+
enum_scopes = definitions.delete(:_scopes)
|
162
|
+
|
163
|
+
default = {}
|
164
|
+
default[:default] = definitions.delete(:_default) if definitions.key?(:_default)
|
165
|
+
|
84
166
|
definitions.each do |name, values|
|
167
|
+
assert_valid_enum_definition_values(values)
|
85
168
|
# statuses = { }
|
86
169
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
87
|
-
name
|
170
|
+
name = name.to_s
|
88
171
|
|
89
|
-
# def self.statuses statuses end
|
90
|
-
detect_enum_conflict!(name, name.
|
91
|
-
|
172
|
+
# def self.statuses() statuses end
|
173
|
+
detect_enum_conflict!(name, name.pluralize, true)
|
174
|
+
singleton_class.define_method(name.pluralize) { enum_values }
|
175
|
+
defined_enums[name] = enum_values
|
92
176
|
|
93
|
-
|
94
|
-
|
95
|
-
klass.send(:detect_enum_conflict!, name, "#{name}=")
|
96
|
-
define_method("#{name}=") { |value|
|
97
|
-
if enum_values.has_key?(value) || value.blank?
|
98
|
-
self[name] = enum_values[value]
|
99
|
-
elsif enum_values.has_value?(value)
|
100
|
-
# Assigning a value directly is not a end-user feature, hence it's not documented.
|
101
|
-
# This is used internally to make building objects from the generated scopes work
|
102
|
-
# as expected, i.e. +Conversation.archived.build.archived?+ should be true.
|
103
|
-
self[name] = value
|
104
|
-
else
|
105
|
-
raise ArgumentError, "'#{value}' is not a valid #{name}"
|
106
|
-
end
|
107
|
-
}
|
177
|
+
detect_enum_conflict!(name, name)
|
178
|
+
detect_enum_conflict!(name, "#{name}=")
|
108
179
|
|
109
|
-
|
110
|
-
|
111
|
-
|
180
|
+
attr = attribute_alias?(name) ? attribute_alias(name) : name
|
181
|
+
|
182
|
+
decorate_attribute_type(attr, **default) do |subtype|
|
183
|
+
EnumType.new(attr, enum_values, subtype)
|
184
|
+
end
|
112
185
|
|
113
|
-
|
114
|
-
|
115
|
-
|
186
|
+
value_method_names = []
|
187
|
+
_enum_methods_module.module_eval do
|
188
|
+
prefix = if enum_prefix == true
|
189
|
+
"#{name}_"
|
190
|
+
elsif enum_prefix
|
191
|
+
"#{enum_prefix}_"
|
192
|
+
end
|
193
|
+
|
194
|
+
suffix = if enum_suffix == true
|
195
|
+
"_#{name}"
|
196
|
+
elsif enum_suffix
|
197
|
+
"_#{enum_suffix}"
|
198
|
+
end
|
116
199
|
|
117
200
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
118
|
-
pairs.each do |
|
119
|
-
enum_values[
|
201
|
+
pairs.each do |label, value|
|
202
|
+
enum_values[label] = value
|
203
|
+
label = label.to_s
|
120
204
|
|
121
|
-
|
122
|
-
|
123
|
-
|
205
|
+
value_method_name = "#{prefix}#{label}#{suffix}"
|
206
|
+
value_method_names << value_method_name
|
207
|
+
define_enum_methods(name, value_method_name, value, enum_scopes)
|
124
208
|
|
125
|
-
|
126
|
-
|
127
|
-
define_method("#{value}!") { update! name => value }
|
209
|
+
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
210
|
+
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
128
211
|
|
129
|
-
|
130
|
-
|
131
|
-
|
212
|
+
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
213
|
+
value_method_names << value_method_alias
|
214
|
+
define_enum_methods(name, value_method_alias, value, enum_scopes)
|
215
|
+
end
|
132
216
|
end
|
133
217
|
end
|
134
|
-
|
218
|
+
detect_negative_enum_conditions!(value_method_names) if enum_scopes != false
|
219
|
+
enum_values.freeze
|
135
220
|
end
|
136
221
|
end
|
137
222
|
|
138
223
|
private
|
224
|
+
class EnumMethods < Module # :nodoc:
|
225
|
+
def initialize(klass)
|
226
|
+
@klass = klass
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
attr_reader :klass
|
231
|
+
|
232
|
+
def define_enum_methods(name, value_method_name, value, enum_scopes)
|
233
|
+
# def active?() status_for_database == 0 end
|
234
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
235
|
+
define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
236
|
+
|
237
|
+
# def active!() update!(status: 0) end
|
238
|
+
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
239
|
+
define_method("#{value_method_name}!") { update!(name => value) }
|
240
|
+
|
241
|
+
# scope :active, -> { where(status: 0) }
|
242
|
+
# scope :not_active, -> { where.not(status: 0) }
|
243
|
+
if enum_scopes != false
|
244
|
+
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
245
|
+
klass.scope value_method_name, -> { where(name => value) }
|
246
|
+
|
247
|
+
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
248
|
+
klass.scope "not_#{value_method_name}", -> { where.not(name => value) }
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
private_constant :EnumMethods
|
253
|
+
|
139
254
|
def _enum_methods_module
|
140
255
|
@_enum_methods_module ||= begin
|
141
|
-
mod =
|
142
|
-
private
|
143
|
-
def save_changed_attribute(attr_name, old)
|
144
|
-
if (mapping = self.class.defined_enums[attr_name.to_s])
|
145
|
-
value = _read_attribute(attr_name)
|
146
|
-
if attribute_changed?(attr_name)
|
147
|
-
if mapping[old] == value
|
148
|
-
clear_attribute_changes([attr_name])
|
149
|
-
end
|
150
|
-
else
|
151
|
-
if old != value
|
152
|
-
set_attribute_was(attr_name, mapping.key(old))
|
153
|
-
end
|
154
|
-
end
|
155
|
-
else
|
156
|
-
super
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
256
|
+
mod = EnumMethods.new(self)
|
160
257
|
include mod
|
161
258
|
mod
|
162
259
|
end
|
163
260
|
end
|
164
261
|
|
262
|
+
def assert_valid_enum_definition_values(values)
|
263
|
+
unless values.is_a?(Hash) || values.all? { |v| v.is_a?(Symbol) } || values.all? { |v| v.is_a?(String) }
|
264
|
+
error_message = <<~MSG
|
265
|
+
Enum values #{values} must be either a hash, an array of symbols, or an array of strings.
|
266
|
+
MSG
|
267
|
+
raise ArgumentError, error_message
|
268
|
+
end
|
269
|
+
|
270
|
+
if values.is_a?(Hash) && values.keys.any?(&:blank?) || values.is_a?(Array) && values.any?(&:blank?)
|
271
|
+
raise ArgumentError, "Enum label name must not be blank."
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
165
275
|
ENUM_CONFLICT_MESSAGE = \
|
166
276
|
"You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
|
167
277
|
"this will generate a %{type} method \"%{method}\", which is already defined " \
|
168
278
|
"by %{source}."
|
279
|
+
private_constant :ENUM_CONFLICT_MESSAGE
|
169
280
|
|
170
281
|
def detect_enum_conflict!(enum_name, method_name, klass_method = false)
|
171
282
|
if klass_method && dangerous_class_method?(method_name)
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
type: 'class',
|
176
|
-
method: method_name,
|
177
|
-
source: 'Active Record'
|
178
|
-
}
|
283
|
+
raise_conflict_error(enum_name, method_name, type: "class")
|
284
|
+
elsif klass_method && method_defined_within?(method_name, Relation)
|
285
|
+
raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
|
179
286
|
elsif !klass_method && dangerous_attribute_method?(method_name)
|
180
|
-
|
181
|
-
enum: enum_name,
|
182
|
-
klass: self.name,
|
183
|
-
type: 'instance',
|
184
|
-
method: method_name,
|
185
|
-
source: 'Active Record'
|
186
|
-
}
|
287
|
+
raise_conflict_error(enum_name, method_name)
|
187
288
|
elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
289
|
+
raise_conflict_error(enum_name, method_name, source: "another enum")
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def raise_conflict_error(enum_name, method_name, type: "instance", source: "Active Record")
|
294
|
+
raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
|
295
|
+
enum: enum_name,
|
296
|
+
klass: name,
|
297
|
+
type: type,
|
298
|
+
method: method_name,
|
299
|
+
source: source
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
def detect_negative_enum_conditions!(method_names)
|
304
|
+
return unless logger
|
305
|
+
|
306
|
+
method_names.select { |m| m.start_with?("not_") }.each do |potential_not|
|
307
|
+
inverted_form = potential_not.sub("not_", "")
|
308
|
+
if method_names.include?(inverted_form)
|
309
|
+
logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
|
310
|
+
" This has caused a conflict with auto generated negative scopes." \
|
311
|
+
" Avoid using enum elements starting with 'not' where the positive form is also an element."
|
312
|
+
end
|
195
313
|
end
|
196
314
|
end
|
197
315
|
end
|