activerecord 5.0.7.2 → 6.0.6.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +844 -1944
- data/MIT-LICENSE +3 -1
- data/README.rdoc +9 -7
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +18 -14
- data/lib/active_record/associations/alias_tracker.rb +24 -34
- data/lib/active_record/associations/association.rb +113 -55
- data/lib/active_record/associations/association_scope.rb +102 -96
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +41 -62
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +93 -254
- data/lib/active_record/associations/collection_proxy.rb +159 -122
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -30
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -85
- 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 +152 -177
- data/lib/active_record/associations/preloader/association.rb +101 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/preloader.rb +94 -103
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -61
- data/lib/active_record/attribute_decorators.rb +38 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -8
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +85 -92
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +20 -49
- data/lib/active_record/attribute_methods/serialization.rb +29 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -66
- data/lib/active_record/attribute_methods/write.rb +34 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -25
- data/lib/active_record/autosave_association.rb +58 -39
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +64 -35
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +558 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +215 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +128 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -28
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +233 -147
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +400 -213
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -79
- data/lib/active_record/connection_adapters/abstract_adapter.rb +373 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -562
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -139
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +137 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +48 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +12 -2
- 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 +19 -18
- 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 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +20 -26
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +378 -308
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +383 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +261 -267
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +143 -40
- data/lib/active_record/core.rb +207 -160
- data/lib/active_record/counter_cache.rb +60 -28
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +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 -87
- data/lib/active_record/enum.rb +67 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -4
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +194 -504
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +150 -99
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +16 -19
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +85 -86
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +134 -100
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +369 -302
- data/lib/active_record/model_schema.rb +160 -127
- data/lib/active_record/nested_attributes.rb +213 -202
- data/lib/active_record/no_touching.rb +12 -3
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +446 -77
- data/lib/active_record/query_cache.rb +13 -12
- data/lib/active_record/querying.rb +37 -24
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +312 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +214 -254
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +98 -52
- data/lib/active_record/relation/calculations.rb +212 -173
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +207 -247
- data/lib/active_record/relation/from_clause.rb +6 -8
- data/lib/active_record/relation/merger.rb +82 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +83 -105
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +488 -332
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -96
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +443 -318
- data/lib/active_record/result.rb +69 -40
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +16 -6
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +51 -26
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +39 -18
- data/lib/active_record/tasks/database_tasks.rb +271 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -91
- data/lib/active_record/tasks/postgresql_database_tasks.rb +77 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +33 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +70 -36
- data/lib/active_record/touch_later.rb +8 -6
- data/lib/active_record/transactions.rb +141 -157
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -48
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +16 -9
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +12 -1
- data/lib/active_record/type/type_map.rb +14 -17
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type.rb +23 -18
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -2
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -5
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +37 -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/migration/migration_generator.rb +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -30
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +138 -52
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
- /data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,121 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module DynamicMatchers #:nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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)
|
7
16
|
match = Method.match(self, name)
|
8
|
-
|
17
|
+
|
18
|
+
if match && match.valid?
|
19
|
+
match.define
|
20
|
+
send(name, *arguments, &block)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
9
24
|
end
|
10
|
-
end
|
11
25
|
|
12
|
-
|
26
|
+
class Method
|
27
|
+
@matchers = []
|
13
28
|
|
14
|
-
|
15
|
-
|
29
|
+
class << self
|
30
|
+
attr_reader :matchers
|
16
31
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
super
|
22
|
-
end
|
23
|
-
end
|
32
|
+
def match(model, name)
|
33
|
+
klass = matchers.find { |k| k.pattern.match?(name) }
|
34
|
+
klass.new(model, name) if klass
|
35
|
+
end
|
24
36
|
|
25
|
-
|
26
|
-
|
37
|
+
def pattern
|
38
|
+
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
39
|
+
end
|
27
40
|
|
28
|
-
|
29
|
-
|
41
|
+
def prefix
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
45
|
+
def suffix
|
46
|
+
""
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
36
|
-
|
37
|
-
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
38
|
-
end
|
50
|
+
attr_reader :model, :name, :attribute_names
|
39
51
|
|
40
|
-
def
|
41
|
-
|
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 }
|
42
57
|
end
|
43
58
|
|
44
|
-
def
|
45
|
-
|
59
|
+
def valid?
|
60
|
+
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
46
61
|
end
|
47
|
-
end
|
48
62
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
def valid?
|
59
|
-
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
60
|
-
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
|
61
70
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#{body}
|
71
|
+
private
|
72
|
+
def body
|
73
|
+
"#{finder}(#{attributes_hash})"
|
66
74
|
end
|
67
|
-
CODE
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def body
|
73
|
-
"#{finder}(#{attributes_hash})"
|
74
|
-
end
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
87
87
|
|
88
|
-
|
89
|
-
|
88
|
+
def finder
|
89
|
+
raise NotImplementedError
|
90
|
+
end
|
90
91
|
end
|
91
|
-
end
|
92
92
|
|
93
|
-
|
94
|
-
|
93
|
+
class FindBy < Method
|
94
|
+
Method.matchers << self
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
96
|
+
def self.prefix
|
97
|
+
"find_by"
|
98
|
+
end
|
99
99
|
|
100
|
-
|
101
|
-
|
100
|
+
def finder
|
101
|
+
"find_by"
|
102
|
+
end
|
102
103
|
end
|
103
|
-
end
|
104
104
|
|
105
|
-
|
106
|
-
|
105
|
+
class FindByBang < Method
|
106
|
+
Method.matchers << self
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
def self.prefix
|
109
|
+
"find_by"
|
110
|
+
end
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
def self.suffix
|
113
|
+
"!"
|
114
|
+
end
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
def finder
|
117
|
+
"find_by!"
|
118
|
+
end
|
118
119
|
end
|
119
|
-
end
|
120
120
|
end
|
121
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,
|
@@ -29,7 +31,9 @@ module ActiveRecord
|
|
29
31
|
# as well. With the above example:
|
30
32
|
#
|
31
33
|
# Conversation.active
|
34
|
+
# Conversation.not_active
|
32
35
|
# Conversation.archived
|
36
|
+
# Conversation.not_archived
|
33
37
|
#
|
34
38
|
# Of course, you can also query them directly if the scopes don't fit your
|
35
39
|
# needs:
|
@@ -95,8 +99,7 @@ module ActiveRecord
|
|
95
99
|
|
96
100
|
module Enum
|
97
101
|
def self.extended(base) # :nodoc:
|
98
|
-
base.class_attribute(:defined_enums, instance_writer: false)
|
99
|
-
base.defined_enums = {}
|
102
|
+
base.class_attribute(:defined_enums, instance_writer: false, default: {})
|
100
103
|
end
|
101
104
|
|
102
105
|
def inherited(base) # :nodoc:
|
@@ -140,23 +143,25 @@ module ActiveRecord
|
|
140
143
|
end
|
141
144
|
end
|
142
145
|
|
143
|
-
|
144
|
-
|
145
|
-
attr_reader :name, :mapping, :subtype
|
146
|
+
private
|
147
|
+
attr_reader :name, :mapping, :subtype
|
146
148
|
end
|
147
149
|
|
148
150
|
def enum(definitions)
|
149
151
|
klass = self
|
150
152
|
enum_prefix = definitions.delete(:_prefix)
|
151
153
|
enum_suffix = definitions.delete(:_suffix)
|
154
|
+
enum_scopes = definitions.delete(:_scopes)
|
152
155
|
definitions.each do |name, values|
|
156
|
+
assert_valid_enum_definition_values(values)
|
153
157
|
# statuses = { }
|
154
158
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
155
|
-
name
|
159
|
+
name = name.to_s
|
156
160
|
|
157
161
|
# def self.statuses() statuses end
|
158
|
-
detect_enum_conflict!(name, name.
|
159
|
-
|
162
|
+
detect_enum_conflict!(name, name.pluralize, true)
|
163
|
+
singleton_class.define_method(name.pluralize) { enum_values }
|
164
|
+
defined_enums[name] = enum_values
|
160
165
|
|
161
166
|
detect_enum_conflict!(name, name)
|
162
167
|
detect_enum_conflict!(name, "#{name}=")
|
@@ -168,7 +173,8 @@ module ActiveRecord
|
|
168
173
|
|
169
174
|
_enum_methods_module.module_eval do
|
170
175
|
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
171
|
-
|
176
|
+
value_method_names = []
|
177
|
+
pairs.each do |label, value|
|
172
178
|
if enum_prefix == true
|
173
179
|
prefix = "#{name}_"
|
174
180
|
elsif enum_prefix
|
@@ -180,23 +186,32 @@ module ActiveRecord
|
|
180
186
|
suffix = "_#{enum_suffix}"
|
181
187
|
end
|
182
188
|
|
183
|
-
value_method_name = "#{prefix}#{
|
184
|
-
|
189
|
+
value_method_name = "#{prefix}#{label}#{suffix}"
|
190
|
+
value_method_names << value_method_name
|
191
|
+
enum_values[label] = value
|
192
|
+
label = label.to_s
|
185
193
|
|
186
|
-
# def active?() status ==
|
194
|
+
# def active?() status == "active" end
|
187
195
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
|
188
|
-
define_method("#{value_method_name}?") { self[attr] ==
|
196
|
+
define_method("#{value_method_name}?") { self[attr] == label }
|
189
197
|
|
190
|
-
# def active!() update!
|
198
|
+
# def active!() update!(status: 0) end
|
191
199
|
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
|
192
200
|
define_method("#{value_method_name}!") { update!(attr => value) }
|
193
201
|
|
194
|
-
# scope :active, -> { where
|
195
|
-
|
196
|
-
|
202
|
+
# scope :active, -> { where(status: 0) }
|
203
|
+
# scope :not_active, -> { where.not(status: 0) }
|
204
|
+
if enum_scopes != false
|
205
|
+
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
206
|
+
klass.scope value_method_name, -> { where(attr => value) }
|
207
|
+
|
208
|
+
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
209
|
+
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
210
|
+
end
|
197
211
|
end
|
212
|
+
klass.send(:detect_negative_enum_conditions!, value_method_names) if enum_scopes != false
|
198
213
|
end
|
199
|
-
|
214
|
+
enum_values.freeze
|
200
215
|
end
|
201
216
|
end
|
202
217
|
|
@@ -209,29 +224,58 @@ module ActiveRecord
|
|
209
224
|
end
|
210
225
|
end
|
211
226
|
|
227
|
+
def assert_valid_enum_definition_values(values)
|
228
|
+
unless values.is_a?(Hash) || values.all? { |v| v.is_a?(Symbol) } || values.all? { |v| v.is_a?(String) }
|
229
|
+
error_message = <<~MSG
|
230
|
+
Enum values #{values} must be either a hash, an array of symbols, or an array of strings.
|
231
|
+
MSG
|
232
|
+
raise ArgumentError, error_message
|
233
|
+
end
|
234
|
+
|
235
|
+
if values.is_a?(Hash) && values.keys.any?(&:blank?) || values.is_a?(Array) && values.any?(&:blank?)
|
236
|
+
raise ArgumentError, "Enum label name must not be blank."
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
212
240
|
ENUM_CONFLICT_MESSAGE = \
|
213
241
|
"You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
|
214
242
|
"this will generate a %{type} method \"%{method}\", which is already defined " \
|
215
243
|
"by %{source}."
|
244
|
+
private_constant :ENUM_CONFLICT_MESSAGE
|
216
245
|
|
217
246
|
def detect_enum_conflict!(enum_name, method_name, klass_method = false)
|
218
247
|
if klass_method && dangerous_class_method?(method_name)
|
219
|
-
raise_conflict_error(enum_name, method_name, type:
|
248
|
+
raise_conflict_error(enum_name, method_name, type: "class")
|
249
|
+
elsif klass_method && method_defined_within?(method_name, Relation)
|
250
|
+
raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
|
220
251
|
elsif !klass_method && dangerous_attribute_method?(method_name)
|
221
252
|
raise_conflict_error(enum_name, method_name)
|
222
253
|
elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
|
223
|
-
raise_conflict_error(enum_name, method_name, source:
|
254
|
+
raise_conflict_error(enum_name, method_name, source: "another enum")
|
224
255
|
end
|
225
256
|
end
|
226
257
|
|
227
|
-
def raise_conflict_error(enum_name, method_name, type:
|
258
|
+
def raise_conflict_error(enum_name, method_name, type: "instance", source: "Active Record")
|
228
259
|
raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
|
229
260
|
enum: enum_name,
|
230
|
-
klass:
|
261
|
+
klass: name,
|
231
262
|
type: type,
|
232
263
|
method: method_name,
|
233
264
|
source: source
|
234
265
|
}
|
235
266
|
end
|
267
|
+
|
268
|
+
def detect_negative_enum_conditions!(method_names)
|
269
|
+
return unless logger
|
270
|
+
|
271
|
+
method_names.select { |m| m.start_with?("not_") }.each do |potential_not|
|
272
|
+
inverted_form = potential_not.sub("not_", "")
|
273
|
+
if method_names.include?(inverted_form)
|
274
|
+
logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
|
275
|
+
" This has caused a conflict with auto generated negative scopes." \
|
276
|
+
" Avoid using enum elements starting with 'not' where the positive form is also an element."
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
236
280
|
end
|
237
281
|
end
|
data/lib/active_record/errors.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module ActiveRecord
|
3
4
|
# = Active Record Errors
|
4
5
|
#
|
5
6
|
# Generic Active Record exception class.
|
@@ -44,10 +45,14 @@ module ActiveRecord
|
|
44
45
|
|
45
46
|
# Raised when connection to the database could not been established (for example when
|
46
47
|
# {ActiveRecord::Base.connection=}[rdoc-ref:ConnectionHandling#connection]
|
47
|
-
# is given a nil object).
|
48
|
+
# is given a +nil+ object).
|
48
49
|
class ConnectionNotEstablished < ActiveRecordError
|
49
50
|
end
|
50
51
|
|
52
|
+
# Raised when a write to the database is attempted on a read only connection.
|
53
|
+
class ReadOnlyError < ActiveRecordError
|
54
|
+
end
|
55
|
+
|
51
56
|
# Raised when Active Record cannot find a record by given id or set of ids.
|
52
57
|
class RecordNotFound < ActiveRecordError
|
53
58
|
attr_reader :model, :primary_key, :id
|
@@ -63,7 +68,7 @@ module ActiveRecord
|
|
63
68
|
|
64
69
|
# Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
|
65
70
|
# {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
|
66
|
-
# methods when a record is invalid and
|
71
|
+
# methods when a record is invalid and cannot be saved.
|
67
72
|
class RecordNotSaved < ActiveRecordError
|
68
73
|
attr_reader :record
|
69
74
|
|
@@ -96,20 +101,13 @@ module ActiveRecord
|
|
96
101
|
#
|
97
102
|
# Wraps the underlying database error as +cause+.
|
98
103
|
class StatementInvalid < ActiveRecordError
|
99
|
-
|
100
|
-
def initialize(message = nil, original_exception = nil)
|
101
|
-
if original_exception
|
102
|
-
ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
|
103
|
-
"Exceptions will automatically capture the original exception.", caller)
|
104
|
-
end
|
105
|
-
|
104
|
+
def initialize(message = nil, sql: nil, binds: nil)
|
106
105
|
super(message || $!.try(:message))
|
106
|
+
@sql = sql
|
107
|
+
@binds = binds
|
107
108
|
end
|
108
109
|
|
109
|
-
|
110
|
-
ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
|
111
|
-
cause
|
112
|
-
end
|
110
|
+
attr_reader :sql, :binds
|
113
111
|
end
|
114
112
|
|
115
113
|
# Defunct wrapper class kept for compatibility.
|
@@ -117,18 +115,60 @@ module ActiveRecord
|
|
117
115
|
class WrappedDatabaseException < StatementInvalid
|
118
116
|
end
|
119
117
|
|
120
|
-
# Raised when a record cannot be inserted because it would violate a uniqueness constraint.
|
118
|
+
# Raised when a record cannot be inserted or updated because it would violate a uniqueness constraint.
|
121
119
|
class RecordNotUnique < WrappedDatabaseException
|
122
120
|
end
|
123
121
|
|
124
|
-
# Raised when a record cannot be inserted or updated because it references a non-existent record
|
122
|
+
# Raised when a record cannot be inserted or updated because it references a non-existent record,
|
123
|
+
# or when a record cannot be deleted because a parent record references it.
|
125
124
|
class InvalidForeignKey < WrappedDatabaseException
|
126
125
|
end
|
127
126
|
|
127
|
+
# Raised when a foreign key constraint cannot be added because the column type does not match the referenced column type.
|
128
|
+
class MismatchedForeignKey < StatementInvalid
|
129
|
+
def initialize(
|
130
|
+
message: nil,
|
131
|
+
sql: nil,
|
132
|
+
binds: nil,
|
133
|
+
table: nil,
|
134
|
+
foreign_key: nil,
|
135
|
+
target_table: nil,
|
136
|
+
primary_key: nil,
|
137
|
+
primary_key_column: nil
|
138
|
+
)
|
139
|
+
if table
|
140
|
+
type = primary_key_column.bigint? ? :bigint : primary_key_column.type
|
141
|
+
msg = <<~EOM.squish
|
142
|
+
Column `#{foreign_key}` on table `#{table}` does not match column `#{primary_key}` on `#{target_table}`,
|
143
|
+
which has type `#{primary_key_column.sql_type}`.
|
144
|
+
To resolve this issue, change the type of the `#{foreign_key}` column on `#{table}` to be :#{type}.
|
145
|
+
(For example `t.#{type} :#{foreign_key}`).
|
146
|
+
EOM
|
147
|
+
else
|
148
|
+
msg = <<~EOM.squish
|
149
|
+
There is a mismatch between the foreign key and primary key column types.
|
150
|
+
Verify that the foreign key column type and the primary key of the associated table match types.
|
151
|
+
EOM
|
152
|
+
end
|
153
|
+
if message
|
154
|
+
msg << "\nOriginal message: #{message}"
|
155
|
+
end
|
156
|
+
super(msg, sql: sql, binds: binds)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Raised when a record cannot be inserted or updated because it would violate a not null constraint.
|
161
|
+
class NotNullViolation < StatementInvalid
|
162
|
+
end
|
163
|
+
|
128
164
|
# Raised when a record cannot be inserted or updated because a value too long for a column type.
|
129
165
|
class ValueTooLong < StatementInvalid
|
130
166
|
end
|
131
167
|
|
168
|
+
# Raised when values that executed are out of range.
|
169
|
+
class RangeError < StatementInvalid
|
170
|
+
end
|
171
|
+
|
132
172
|
# Raised when number of bind variables in statement given to +:condition+ key
|
133
173
|
# (for example, when using {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method)
|
134
174
|
# does not match number of expected values supplied.
|
@@ -143,7 +183,7 @@ module ActiveRecord
|
|
143
183
|
class NoDatabaseError < StatementInvalid
|
144
184
|
end
|
145
185
|
|
146
|
-
# Raised when
|
186
|
+
# Raised when PostgreSQL returns 'cached plan must not change result type' and
|
147
187
|
# we cannot retry gracefully (e.g. inside a transaction)
|
148
188
|
class PreparedStatementCacheExpired < StatementInvalid
|
149
189
|
end
|
@@ -166,7 +206,6 @@ module ActiveRecord
|
|
166
206
|
super("Stale object error.")
|
167
207
|
end
|
168
208
|
end
|
169
|
-
|
170
209
|
end
|
171
210
|
|
172
211
|
# Raised when association is being configured improperly or user tries to use
|
@@ -285,8 +324,65 @@ module ActiveRecord
|
|
285
324
|
class TransactionIsolationError < ActiveRecordError
|
286
325
|
end
|
287
326
|
|
327
|
+
# TransactionRollbackError will be raised when a transaction is rolled
|
328
|
+
# back by the database due to a serialization failure or a deadlock.
|
329
|
+
#
|
330
|
+
# See the following:
|
331
|
+
#
|
332
|
+
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
333
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
|
334
|
+
class TransactionRollbackError < StatementInvalid
|
335
|
+
end
|
336
|
+
|
337
|
+
# SerializationFailure will be raised when a transaction is rolled
|
338
|
+
# back by the database due to a serialization failure.
|
339
|
+
class SerializationFailure < TransactionRollbackError
|
340
|
+
end
|
341
|
+
|
342
|
+
# Deadlocked will be raised when a transaction is rolled
|
343
|
+
# back by the database when a deadlock is encountered.
|
344
|
+
class Deadlocked < TransactionRollbackError
|
345
|
+
end
|
346
|
+
|
288
347
|
# IrreversibleOrderError is raised when a relation's order is too complex for
|
289
348
|
# +reverse_order+ to automatically reverse.
|
290
349
|
class IrreversibleOrderError < ActiveRecordError
|
291
350
|
end
|
351
|
+
|
352
|
+
# LockWaitTimeout will be raised when lock wait timeout exceeded.
|
353
|
+
class LockWaitTimeout < StatementInvalid
|
354
|
+
end
|
355
|
+
|
356
|
+
# StatementTimeout will be raised when statement timeout exceeded.
|
357
|
+
class StatementTimeout < StatementInvalid
|
358
|
+
end
|
359
|
+
|
360
|
+
# QueryCanceled will be raised when canceling statement due to user request.
|
361
|
+
class QueryCanceled < StatementInvalid
|
362
|
+
end
|
363
|
+
|
364
|
+
# UnknownAttributeReference is raised when an unknown and potentially unsafe
|
365
|
+
# value is passed to a query method when allow_unsafe_raw_sql is set to
|
366
|
+
# :disabled. For example, passing a non column name value to a relation's
|
367
|
+
# #order method might cause this exception.
|
368
|
+
#
|
369
|
+
# When working around this exception, caution should be taken to avoid SQL
|
370
|
+
# injection vulnerabilities when passing user-provided values to query
|
371
|
+
# methods. Known-safe values can be passed to query methods by wrapping them
|
372
|
+
# in Arel.sql.
|
373
|
+
#
|
374
|
+
# For example, with allow_unsafe_raw_sql set to :disabled, the following
|
375
|
+
# code would raise this exception:
|
376
|
+
#
|
377
|
+
# Post.order("length(title)").first
|
378
|
+
#
|
379
|
+
# The desired result can be accomplished by wrapping the known-safe string
|
380
|
+
# in Arel.sql:
|
381
|
+
#
|
382
|
+
# Post.order(Arel.sql("length(title)")).first
|
383
|
+
#
|
384
|
+
# Again, such a workaround should *not* be used when passing user-provided
|
385
|
+
# values, such as request parameters or model attributes to query methods.
|
386
|
+
class UnknownAttributeReference < ActiveRecordError
|
387
|
+
end
|
292
388
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/explain_registry"
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module Explain
|
@@ -17,7 +18,7 @@ module ActiveRecord
|
|
17
18
|
# Returns a formatted string ready to be logged.
|
18
19
|
def exec_explain(queries) # :nodoc:
|
19
20
|
str = queries.map do |sql, binds|
|
20
|
-
msg = "EXPLAIN for: #{sql}"
|
21
|
+
msg = +"EXPLAIN for: #{sql}"
|
21
22
|
unless binds.empty?
|
22
23
|
msg << " "
|
23
24
|
msg << binds.map { |attr| render_bind(attr) }.inspect
|
@@ -35,7 +36,6 @@ module ActiveRecord
|
|
35
36
|
end
|
36
37
|
|
37
38
|
private
|
38
|
-
|
39
39
|
def render_bind(attr)
|
40
40
|
value = if attr.type.binary? && attr.value
|
41
41
|
"<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/notifications"
|
4
|
+
require "active_record/explain_registry"
|
3
5
|
|
4
6
|
module ActiveRecord
|
5
7
|
class ExplainSubscriber # :nodoc:
|
@@ -18,10 +20,13 @@ module ActiveRecord
|
|
18
20
|
#
|
19
21
|
# On the other hand, we want to monitor the performance of our real database
|
20
22
|
# queries, not the performance of the access to the query cache.
|
21
|
-
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN
|
23
|
+
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
|
22
24
|
EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
|
23
25
|
def ignore_payload?(payload)
|
24
|
-
payload[:exception] ||
|
26
|
+
payload[:exception] ||
|
27
|
+
payload[:cached] ||
|
28
|
+
IGNORED_PAYLOADS.include?(payload[:name]) ||
|
29
|
+
payload[:sql] !~ EXPLAINED_SQLS
|
25
30
|
end
|
26
31
|
|
27
32
|
ActiveSupport::Notifications.subscribe("sql.active_record", new)
|