activerecord 5.0.7.2 → 6.1.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 +829 -2015
- data/MIT-LICENSE +3 -1
- data/README.rdoc +11 -9
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record.rb +37 -29
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +30 -18
- data/lib/active_record/associations.rb +1714 -1596
- data/lib/active_record/associations/alias_tracker.rb +36 -42
- data/lib/active_record/associations/association.rb +143 -68
- data/lib/active_record/associations/association_scope.rb +98 -94
- data/lib/active_record/associations/belongs_to_association.rb +76 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +27 -28
- data/lib/active_record/associations/builder/belongs_to.rb +52 -60
- data/lib/active_record/associations/builder/collection_association.rb +12 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
- data/lib/active_record/associations/builder/has_many.rb +10 -2
- data/lib/active_record/associations/builder/has_one.rb +35 -2
- data/lib/active_record/associations/builder/singular_association.rb +5 -1
- data/lib/active_record/associations/collection_association.rb +104 -259
- data/lib/active_record/associations/collection_proxy.rb +169 -125
- data/lib/active_record/associations/foreign_association.rb +22 -0
- data/lib/active_record/associations/has_many_association.rb +46 -31
- data/lib/active_record/associations/has_many_through_association.rb +66 -46
- data/lib/active_record/associations/has_one_association.rb +71 -52
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +169 -180
- data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/preloader.rb +97 -104
- data/lib/active_record/associations/preloader/association.rb +109 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/attribute_assignment.rb +55 -60
- data/lib/active_record/attribute_methods.rb +111 -141
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
- data/lib/active_record/attribute_methods/dirty.rb +172 -112
- data/lib/active_record/attribute_methods/primary_key.rb +88 -91
- data/lib/active_record/attribute_methods/query.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +18 -50
- data/lib/active_record/attribute_methods/serialization.rb +38 -10
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
- data/lib/active_record/attribute_methods/write.rb +25 -32
- data/lib/active_record/attributes.rb +69 -31
- data/lib/active_record/autosave_association.rb +102 -66
- data/lib/active_record/base.rb +16 -25
- data/lib/active_record/callbacks.rb +202 -43
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -12
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
- data/lib/active_record/connection_adapters/column.rb +55 -13
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -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 +79 -49
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -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 +20 -12
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
- 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 +6 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
- 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/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 -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 +18 -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/quoting.rb +98 -38
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -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 +426 -324
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
- data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -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 +5 -6
- 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 +282 -290
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +287 -45
- data/lib/active_record/core.rb +385 -181
- data/lib/active_record/counter_cache.rb +60 -28
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -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/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -87
- data/lib/active_record/enum.rb +122 -47
- data/lib/active_record/errors.rb +153 -22
- data/lib/active_record/explain.rb +13 -8
- 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 +20 -22
- 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 +246 -507
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +168 -95
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +114 -25
- data/lib/active_record/internal_metadata.rb +30 -24
- data/lib/active_record/legacy_yaml_adapter.rb +11 -5
- data/lib/active_record/locking/optimistic.rb +81 -85
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +68 -31
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/migration.rb +439 -342
- data/lib/active_record/migration/command_recorder.rb +152 -98
- data/lib/active_record/migration/compatibility.rb +229 -60
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/model_schema.rb +230 -122
- data/lib/active_record/nested_attributes.rb +213 -203
- data/lib/active_record/no_touching.rb +11 -2
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +471 -97
- data/lib/active_record/query_cache.rb +23 -12
- data/lib/active_record/querying.rb +43 -25
- data/lib/active_record/railtie.rb +155 -43
- 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 +507 -195
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +245 -269
- data/lib/active_record/relation.rb +475 -324
- data/lib/active_record/relation/batches.rb +125 -72
- data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
- data/lib/active_record/relation/calculations.rb +267 -171
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +238 -248
- data/lib/active_record/relation/from_clause.rb +7 -9
- data/lib/active_record/relation/merger.rb +95 -77
- data/lib/active_record/relation/predicate_builder.rb +109 -110
- data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +654 -374
- data/lib/active_record/relation/record_fetch_warning.rb +8 -6
- data/lib/active_record/relation/spawn_methods.rb +15 -14
- data/lib/active_record/relation/where_clause.rb +171 -109
- data/lib/active_record/result.rb +88 -51
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +73 -100
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +101 -69
- data/lib/active_record/schema_migration.rb +16 -12
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +39 -30
- data/lib/active_record/secure_token.rb +19 -9
- data/lib/active_record/serialization.rb +7 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +80 -29
- data/lib/active_record/store.rb +122 -42
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +51 -39
- data/lib/active_record/tasks/database_tasks.rb +332 -115
- data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
- data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +26 -24
- data/lib/active_record/transactions.rb +121 -184
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +29 -17
- 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 +20 -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_caster.rb +4 -2
- data/lib/active_record/type_caster/connection.rb +17 -13
- data/lib/active_record/type_caster/map.rb +10 -6
- data/lib/active_record/validations.rb +8 -5
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +4 -3
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +52 -45
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +54 -0
- 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.rb +70 -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 +72 -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/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.rb +13 -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/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- 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/migration.rb +22 -3
- data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
- 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 → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +141 -57
- 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.rb +0 -213
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute_decorators.rb +0 -67
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
- 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/base_handler.rb +0 -17
- 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/relation/where_clause_factory.rb +0 -38
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
class StatementPool # :nodoc:
|
@@ -6,7 +8,7 @@ module ActiveRecord
|
|
6
8
|
DEFAULT_STATEMENT_LIMIT = 1000
|
7
9
|
|
8
10
|
def initialize(statement_limit = nil)
|
9
|
-
@cache = Hash.new { |h,pid| h[pid] = {} }
|
11
|
+
@cache = Hash.new { |h, pid| h[pid] = {} }
|
10
12
|
@statement_limit = statement_limit || DEFAULT_STATEMENT_LIMIT
|
11
13
|
end
|
12
14
|
|
@@ -46,14 +48,13 @@ module ActiveRecord
|
|
46
48
|
end
|
47
49
|
|
48
50
|
private
|
51
|
+
def cache
|
52
|
+
@cache[Process.pid]
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def dealloc(stmt)
|
55
|
-
raise NotImplementedError
|
56
|
-
end
|
55
|
+
def dealloc(stmt)
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionHandling
|
3
|
-
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
|
5
|
+
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
4
6
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
5
7
|
|
6
8
|
# Establishes the connection to the database. Accepts a hash as input where
|
@@ -44,44 +46,226 @@ module ActiveRecord
|
|
44
46
|
#
|
45
47
|
# The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
|
46
48
|
# may be returned on an error.
|
47
|
-
def establish_connection(
|
48
|
-
|
49
|
+
def establish_connection(config_or_env = nil)
|
50
|
+
config_or_env ||= DEFAULT_ENV.call.to_sym
|
51
|
+
db_config, owner_name = resolve_config_for_connection(config_or_env)
|
52
|
+
connection_handler.establish_connection(db_config, owner_name: owner_name, role: current_role, shard: current_shard)
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
# Connects a model to the databases specified. The +database+ keyword
|
56
|
+
# takes a hash consisting of a +role+ and a +database_key+.
|
57
|
+
#
|
58
|
+
# This will create a connection handler for switching between connections,
|
59
|
+
# look up the config hash using the +database_key+ and finally
|
60
|
+
# establishes a connection to that config.
|
61
|
+
#
|
62
|
+
# class AnimalsModel < ApplicationRecord
|
63
|
+
# self.abstract_class = true
|
64
|
+
#
|
65
|
+
# connects_to database: { writing: :primary, reading: :primary_replica }
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# +connects_to+ also supports horizontal sharding. The horizontal sharding API
|
69
|
+
# also supports read replicas. Connect a model to a list of shards like this:
|
70
|
+
#
|
71
|
+
# class AnimalsModel < ApplicationRecord
|
72
|
+
# self.abstract_class = true
|
73
|
+
#
|
74
|
+
# connects_to shards: {
|
75
|
+
# default: { writing: :primary, reading: :primary_replica },
|
76
|
+
# shard_two: { writing: :primary_shard_two, reading: :primary_shard_replica_two }
|
77
|
+
# }
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# Returns an array of database connections.
|
81
|
+
def connects_to(database: {}, shards: {})
|
82
|
+
raise NotImplementedError, "`connects_to` can only be called on ActiveRecord::Base or abstract classes" unless self == Base || abstract_class?
|
54
83
|
|
55
|
-
|
56
|
-
raise
|
84
|
+
if database.present? && shards.present?
|
85
|
+
raise ArgumentError, "`connects_to` can only accept a `database` or `shards` argument, but not both arguments."
|
57
86
|
end
|
58
87
|
|
59
|
-
|
60
|
-
|
61
|
-
|
88
|
+
connections = []
|
89
|
+
|
90
|
+
database.each do |role, database_key|
|
91
|
+
db_config, owner_name = resolve_config_for_connection(database_key)
|
92
|
+
handler = lookup_connection_handler(role.to_sym)
|
93
|
+
|
94
|
+
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
95
|
+
end
|
96
|
+
|
97
|
+
shards.each do |shard, database_keys|
|
98
|
+
database_keys.each do |role, database_key|
|
99
|
+
db_config, owner_name = resolve_config_for_connection(database_key)
|
100
|
+
handler = lookup_connection_handler(role.to_sym)
|
101
|
+
|
102
|
+
connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
connections
|
62
107
|
end
|
63
108
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
109
|
+
# Connects to a role (ex writing, reading or a custom role) and/or
|
110
|
+
# shard for the duration of the block. At the end of the block the
|
111
|
+
# connection will be returned to the original role / shard.
|
112
|
+
#
|
113
|
+
# If only a role is passed, Active Record will look up the connection
|
114
|
+
# based on the requested role. If a non-established role is requested
|
115
|
+
# an `ActiveRecord::ConnectionNotEstablished` error will be raised:
|
116
|
+
#
|
117
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
118
|
+
# Dog.create! # creates dog using dog writing connection
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
122
|
+
# Dog.create! # throws exception because we're on a replica
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# When swapping to a shard, the role must be passed as well. If a non-existent
|
126
|
+
# shard is passed, an `ActiveRecord::ConnectionNotEstablished` error will be
|
127
|
+
# raised.
|
128
|
+
#
|
129
|
+
# When a shard and role is passed, Active Record will first lookup the role,
|
130
|
+
# and then look up the connection by shard key.
|
131
|
+
#
|
132
|
+
# ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
|
133
|
+
# Dog.first # finds first Dog record stored on the shard one replica
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# The database kwarg is deprecated and will be removed in 6.2.0 without replacement.
|
137
|
+
def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
|
138
|
+
if legacy_connection_handling
|
139
|
+
if self != Base
|
140
|
+
raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
|
141
|
+
end
|
142
|
+
else
|
143
|
+
if self != Base && !abstract_class
|
144
|
+
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
if database && (role || shard)
|
149
|
+
raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
|
150
|
+
elsif database
|
151
|
+
ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 6.2.0 without replacement.")
|
152
|
+
|
153
|
+
if database.is_a?(Hash)
|
154
|
+
role, database = database.first
|
155
|
+
role = role.to_sym
|
156
|
+
end
|
157
|
+
|
158
|
+
db_config, owner_name = resolve_config_for_connection(database)
|
159
|
+
handler = lookup_connection_handler(role)
|
160
|
+
|
161
|
+
handler.establish_connection(db_config, owner_name: owner_name, role: role)
|
162
|
+
|
163
|
+
with_handler(role, &blk)
|
164
|
+
elsif role || shard
|
165
|
+
unless role
|
166
|
+
raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
|
167
|
+
end
|
168
|
+
|
169
|
+
with_role_and_shard(role, shard, prevent_writes, &blk)
|
170
|
+
else
|
171
|
+
raise ArgumentError, "must provide a `shard` and/or `role`."
|
68
172
|
end
|
173
|
+
end
|
69
174
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
175
|
+
# Connects a role and/or shard to the provided connection names. Optionally `prevent_writes`
|
176
|
+
# can be passed to block writes on a connection. `reading` will automatically set
|
177
|
+
# `prevent_writes` to true.
|
178
|
+
#
|
179
|
+
# `connected_to_many` is an alternative to deeply nested `connected_to` blocks.
|
180
|
+
#
|
181
|
+
# Usage:
|
182
|
+
#
|
183
|
+
# ActiveRecord::Base.connected_to(AnimalsRecord, MealsRecord], role: :reading) do
|
184
|
+
# Dog.first # Read from animals replica
|
185
|
+
# Dinner.first # Read from meals replica
|
186
|
+
# Person.first # Read from primary writer
|
187
|
+
# end
|
188
|
+
def connected_to_many(classes, role:, shard: nil, prevent_writes: false)
|
189
|
+
if legacy_connection_handling
|
190
|
+
raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
|
74
191
|
end
|
75
192
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
193
|
+
if self != Base || classes.include?(Base)
|
194
|
+
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
195
|
+
end
|
196
|
+
|
197
|
+
prevent_writes = true if role == reading_role
|
198
|
+
|
199
|
+
connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
|
200
|
+
yield
|
201
|
+
ensure
|
202
|
+
connected_to_stack.pop
|
203
|
+
end
|
204
|
+
|
205
|
+
# Use a specified connection.
|
206
|
+
#
|
207
|
+
# This method is useful for ensuring that a specific connection is
|
208
|
+
# being used. For example, when booting a console in readonly mode.
|
209
|
+
#
|
210
|
+
# It is not recommended to use this method in a request since it
|
211
|
+
# does not yield to a block like `connected_to`.
|
212
|
+
def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
|
213
|
+
if legacy_connection_handling
|
214
|
+
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
215
|
+
end
|
216
|
+
|
217
|
+
prevent_writes = true if role == reading_role
|
218
|
+
|
219
|
+
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
220
|
+
end
|
221
|
+
|
222
|
+
# Prevent writing to the database regardless of role.
|
223
|
+
#
|
224
|
+
# In some cases you may want to prevent writes to the database
|
225
|
+
# even if you are on a database that can write. `while_preventing_writes`
|
226
|
+
# will prevent writes to the database for the duration of the block.
|
227
|
+
#
|
228
|
+
# This method does not provide the same protection as a readonly
|
229
|
+
# user and is meant to be a safeguard against accidental writes.
|
230
|
+
#
|
231
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
232
|
+
# method.
|
233
|
+
def while_preventing_writes(enabled = true, &block)
|
234
|
+
if legacy_connection_handling
|
235
|
+
connection_handler.while_preventing_writes(enabled, &block)
|
236
|
+
else
|
237
|
+
connected_to(role: current_role, prevent_writes: enabled, &block)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Returns true if role is the current connected role.
|
242
|
+
#
|
243
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
244
|
+
# ActiveRecord::Base.connected_to?(role: :writing) #=> true
|
245
|
+
# ActiveRecord::Base.connected_to?(role: :reading) #=> false
|
246
|
+
# end
|
247
|
+
def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
|
248
|
+
current_role == role.to_sym && current_shard == shard.to_sym
|
249
|
+
end
|
250
|
+
|
251
|
+
def lookup_connection_handler(handler_key) # :nodoc:
|
252
|
+
if ActiveRecord::Base.legacy_connection_handling
|
253
|
+
handler_key ||= ActiveRecord::Base.writing_role
|
254
|
+
connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
255
|
+
else
|
256
|
+
ActiveRecord::Base.connection_handler
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Clears the query cache for all connections associated with the current thread.
|
261
|
+
def clear_query_caches_for_current_thread
|
262
|
+
if ActiveRecord::Base.legacy_connection_handling
|
263
|
+
ActiveRecord::Base.connection_handlers.each_value do |handler|
|
264
|
+
clear_on_handler(handler)
|
84
265
|
end
|
266
|
+
else
|
267
|
+
clear_on_handler(ActiveRecord::Base.connection_handler)
|
268
|
+
end
|
85
269
|
end
|
86
270
|
|
87
271
|
# Returns the connection currently associated with the class. This can
|
@@ -93,21 +277,16 @@ module ActiveRecord
|
|
93
277
|
|
94
278
|
attr_writer :connection_specification_name
|
95
279
|
|
96
|
-
# Return the specification
|
97
|
-
# in the parent.
|
280
|
+
# Return the connection specification name from the current class or its parent.
|
98
281
|
def connection_specification_name
|
99
282
|
if !defined?(@connection_specification_name) || @connection_specification_name.nil?
|
100
|
-
return self == Base ?
|
283
|
+
return self == Base ? Base.name : superclass.connection_specification_name
|
101
284
|
end
|
102
285
|
@connection_specification_name
|
103
286
|
end
|
104
287
|
|
105
|
-
def
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
def connection_id=(connection_id)
|
110
|
-
ActiveRecord::RuntimeRegistry.connection_id = connection_id
|
288
|
+
def primary_class? # :nodoc:
|
289
|
+
self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
|
111
290
|
end
|
112
291
|
|
113
292
|
# Returns the configuration of the associated connection as a hash:
|
@@ -117,32 +296,44 @@ module ActiveRecord
|
|
117
296
|
#
|
118
297
|
# Please use only for reading.
|
119
298
|
def connection_config
|
120
|
-
connection_pool.
|
299
|
+
connection_pool.db_config.configuration_hash
|
300
|
+
end
|
301
|
+
deprecate connection_config: "Use connection_db_config instead"
|
302
|
+
|
303
|
+
# Returns the db_config object from the associated connection:
|
304
|
+
#
|
305
|
+
# ActiveRecord::Base.connection_db_config
|
306
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
307
|
+
# @name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>
|
308
|
+
#
|
309
|
+
# Use only for reading.
|
310
|
+
def connection_db_config
|
311
|
+
connection_pool.db_config
|
121
312
|
end
|
122
313
|
|
123
314
|
def connection_pool
|
124
|
-
connection_handler.retrieve_connection_pool(connection_specification_name)
|
315
|
+
connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard) || raise(ConnectionNotEstablished)
|
125
316
|
end
|
126
317
|
|
127
318
|
def retrieve_connection
|
128
|
-
connection_handler.retrieve_connection(connection_specification_name)
|
319
|
+
connection_handler.retrieve_connection(connection_specification_name, role: current_role, shard: current_shard)
|
129
320
|
end
|
130
321
|
|
131
322
|
# Returns +true+ if Active Record is connected.
|
132
323
|
def connected?
|
133
|
-
connection_handler.connected?(connection_specification_name)
|
324
|
+
connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
|
134
325
|
end
|
135
326
|
|
136
327
|
def remove_connection(name = nil)
|
137
328
|
name ||= @connection_specification_name if defined?(@connection_specification_name)
|
138
|
-
# if removing a connection that
|
329
|
+
# if removing a connection that has a pool, we reset the
|
139
330
|
# connection_specification_name so it will use the parent
|
140
331
|
# pool.
|
141
|
-
if connection_handler.retrieve_connection_pool(name)
|
332
|
+
if connection_handler.retrieve_connection_pool(name, role: current_role, shard: current_shard)
|
142
333
|
self.connection_specification_name = nil
|
143
334
|
end
|
144
335
|
|
145
|
-
connection_handler.
|
336
|
+
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
|
146
337
|
end
|
147
338
|
|
148
339
|
def clear_cache! # :nodoc:
|
@@ -150,6 +341,57 @@ module ActiveRecord
|
|
150
341
|
end
|
151
342
|
|
152
343
|
delegate :clear_active_connections!, :clear_reloadable_connections!,
|
153
|
-
:clear_all_connections!, :to
|
344
|
+
:clear_all_connections!, :flush_idle_connections!, to: :connection_handler
|
345
|
+
|
346
|
+
private
|
347
|
+
def clear_on_handler(handler)
|
348
|
+
handler.all_connection_pools.each do |pool|
|
349
|
+
pool.connection.clear_query_cache if pool.active_connection?
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def resolve_config_for_connection(config_or_env)
|
354
|
+
raise "Anonymous class is not allowed." unless name
|
355
|
+
|
356
|
+
owner_name = primary_class? ? Base.name : name
|
357
|
+
self.connection_specification_name = owner_name
|
358
|
+
|
359
|
+
db_config = Base.configurations.resolve(config_or_env)
|
360
|
+
[db_config, owner_name]
|
361
|
+
end
|
362
|
+
|
363
|
+
def with_handler(handler_key, &blk)
|
364
|
+
handler = lookup_connection_handler(handler_key)
|
365
|
+
swap_connection_handler(handler, &blk)
|
366
|
+
end
|
367
|
+
|
368
|
+
def with_role_and_shard(role, shard, prevent_writes)
|
369
|
+
prevent_writes = true if role == reading_role
|
370
|
+
|
371
|
+
if ActiveRecord::Base.legacy_connection_handling
|
372
|
+
with_handler(role.to_sym) do
|
373
|
+
connection_handler.while_preventing_writes(prevent_writes) do
|
374
|
+
self.connected_to_stack << { shard: shard, klasses: [self] }
|
375
|
+
yield
|
376
|
+
end
|
377
|
+
end
|
378
|
+
else
|
379
|
+
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
380
|
+
return_value = yield
|
381
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
382
|
+
return_value
|
383
|
+
end
|
384
|
+
ensure
|
385
|
+
self.connected_to_stack.pop
|
386
|
+
end
|
387
|
+
|
388
|
+
def swap_connection_handler(handler, &blk) # :nodoc:
|
389
|
+
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
390
|
+
return_value = yield
|
391
|
+
return_value.load if return_value.is_a? ActiveRecord::Relation
|
392
|
+
return_value
|
393
|
+
ensure
|
394
|
+
ActiveRecord::Base.connection_handler = old_handler
|
395
|
+
end
|
154
396
|
end
|
155
397
|
end
|
data/lib/active_record/core.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
require "active_support/core_ext/hash/indifferent_access"
|
5
|
+
require "active_support/core_ext/string/filters"
|
6
|
+
require "active_support/parameter_filter"
|
7
|
+
require "concurrent/map"
|
5
8
|
|
6
9
|
module ActiveRecord
|
7
10
|
module Core
|
@@ -16,9 +19,28 @@ module ActiveRecord
|
|
16
19
|
# retrieved on both a class and instance level by calling +logger+.
|
17
20
|
mattr_accessor :logger, instance_writer: false
|
18
21
|
|
22
|
+
##
|
23
|
+
# :singleton-method:
|
24
|
+
#
|
25
|
+
# Specifies if the methods calling database queries should be logged below
|
26
|
+
# their relevant queries. Defaults to false.
|
27
|
+
mattr_accessor :verbose_query_logs, instance_writer: false, default: false
|
28
|
+
|
29
|
+
##
|
30
|
+
# :singleton-method:
|
31
|
+
#
|
32
|
+
# Specifies the names of the queues used by background jobs.
|
33
|
+
mattr_accessor :queues, instance_accessor: false, default: {}
|
34
|
+
|
35
|
+
##
|
36
|
+
# :singleton-method:
|
37
|
+
#
|
38
|
+
# Specifies the job used to destroy associations in the background
|
39
|
+
class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
|
40
|
+
|
19
41
|
##
|
20
42
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
21
|
-
# as
|
43
|
+
# as an ActiveRecord::DatabaseConfigurations object.
|
22
44
|
#
|
23
45
|
# For example, the following database.yml...
|
24
46
|
#
|
@@ -32,22 +54,18 @@ module ActiveRecord
|
|
32
54
|
#
|
33
55
|
# ...would result in ActiveRecord::Base.configurations to look like this:
|
34
56
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# 'adapter' => 'sqlite3',
|
42
|
-
# 'database' => 'db/production.sqlite3'
|
43
|
-
# }
|
44
|
-
# }
|
57
|
+
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
58
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
59
|
+
# @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
|
60
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
61
|
+
# @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
|
62
|
+
# ]>
|
45
63
|
def self.configurations=(config)
|
46
|
-
@@configurations = ActiveRecord::
|
64
|
+
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
47
65
|
end
|
48
66
|
self.configurations = {}
|
49
67
|
|
50
|
-
# Returns fully resolved
|
68
|
+
# Returns fully resolved ActiveRecord::DatabaseConfigurations object
|
51
69
|
def self.configurations
|
52
70
|
@@configurations
|
53
71
|
end
|
@@ -56,8 +74,7 @@ module ActiveRecord
|
|
56
74
|
# :singleton-method:
|
57
75
|
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
|
58
76
|
# dates and times from the database. This is set to :utc by default.
|
59
|
-
mattr_accessor :default_timezone, instance_writer: false
|
60
|
-
self.default_timezone = :utc
|
77
|
+
mattr_accessor :default_timezone, instance_writer: false, default: :utc
|
61
78
|
|
62
79
|
##
|
63
80
|
# :singleton-method:
|
@@ -67,41 +84,36 @@ module ActiveRecord
|
|
67
84
|
# ActiveRecord::Schema file which can be loaded into any database that
|
68
85
|
# supports migrations. Use :ruby if you want to have different database
|
69
86
|
# adapters for, e.g., your development and test environments.
|
70
|
-
mattr_accessor :schema_format, instance_writer: false
|
71
|
-
self.schema_format = :ruby
|
87
|
+
mattr_accessor :schema_format, instance_writer: false, default: :ruby
|
72
88
|
|
73
89
|
##
|
74
90
|
# :singleton-method:
|
75
|
-
# Specifies if an error should be raised
|
91
|
+
# Specifies if an error should be raised if the query has an order being
|
76
92
|
# ignored when doing batch queries. Useful in applications where the
|
77
|
-
#
|
78
|
-
mattr_accessor :
|
79
|
-
self.error_on_ignored_order_or_limit = false
|
93
|
+
# scope being ignored is error-worthy, rather than a warning.
|
94
|
+
mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
|
80
95
|
|
81
96
|
##
|
82
97
|
# :singleton-method:
|
83
98
|
# Specify whether or not to use timestamps for migration versions
|
84
|
-
mattr_accessor :timestamped_migrations, instance_writer: false
|
85
|
-
self.timestamped_migrations = true
|
99
|
+
mattr_accessor :timestamped_migrations, instance_writer: false, default: true
|
86
100
|
|
87
101
|
##
|
88
102
|
# :singleton-method:
|
89
103
|
# Specify whether schema dump should happen at the end of the
|
90
|
-
# db:migrate
|
104
|
+
# db:migrate rails command. This is true by default, which is useful for the
|
91
105
|
# development environment. This should ideally be false in the production
|
92
106
|
# environment where dumping schema is rarely needed.
|
93
|
-
mattr_accessor :dump_schema_after_migration, instance_writer: false
|
94
|
-
self.dump_schema_after_migration = true
|
107
|
+
mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
|
95
108
|
|
96
109
|
##
|
97
110
|
# :singleton-method:
|
98
|
-
# Specifies which database schemas to dump when calling db:
|
111
|
+
# Specifies which database schemas to dump when calling db:schema:dump.
|
99
112
|
# If the value is :schema_search_path (the default), any schemas listed in
|
100
113
|
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
101
114
|
# of schema_search_path, or a string of comma separated schemas for a
|
102
115
|
# custom list.
|
103
|
-
mattr_accessor :dump_schemas, instance_writer: false
|
104
|
-
self.dump_schemas = :schema_search_path
|
116
|
+
mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
|
105
117
|
|
106
118
|
##
|
107
119
|
# :singleton-method:
|
@@ -110,122 +122,278 @@ module ActiveRecord
|
|
110
122
|
# be used to identify queries which load thousands of records and
|
111
123
|
# potentially cause memory bloat.
|
112
124
|
mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
|
113
|
-
|
125
|
+
|
126
|
+
##
|
127
|
+
# :singleton-method:
|
128
|
+
# Show a warning when Rails couldn't parse your database.yml
|
129
|
+
# for multiple databases.
|
130
|
+
mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
|
114
131
|
|
115
132
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
116
133
|
|
117
|
-
|
134
|
+
class_attribute :belongs_to_required_by_default, instance_accessor: false
|
135
|
+
|
136
|
+
##
|
137
|
+
# :singleton-method:
|
138
|
+
# Set the application to log or raise when an association violates strict loading.
|
139
|
+
# Defaults to :raise.
|
140
|
+
mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
|
141
|
+
|
142
|
+
class_attribute :strict_loading_by_default, instance_accessor: false, default: false
|
143
|
+
|
144
|
+
mattr_accessor :writing_role, instance_accessor: false, default: :writing
|
145
|
+
|
146
|
+
mattr_accessor :reading_role, instance_accessor: false, default: :reading
|
147
|
+
|
148
|
+
mattr_accessor :has_many_inversing, instance_accessor: false, default: false
|
118
149
|
|
119
150
|
class_attribute :default_connection_handler, instance_writer: false
|
120
151
|
|
152
|
+
class_attribute :default_role, instance_writer: false
|
153
|
+
|
154
|
+
class_attribute :default_shard, instance_writer: false
|
155
|
+
|
156
|
+
mattr_accessor :legacy_connection_handling, instance_writer: false, default: true
|
157
|
+
|
158
|
+
self.filter_attributes = []
|
159
|
+
|
121
160
|
def self.connection_handler
|
122
|
-
|
161
|
+
Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
|
123
162
|
end
|
124
163
|
|
125
164
|
def self.connection_handler=(handler)
|
126
|
-
|
165
|
+
Thread.current.thread_variable_set(:ar_connection_handler, handler)
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.connection_handlers
|
169
|
+
unless legacy_connection_handling
|
170
|
+
raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
|
171
|
+
end
|
172
|
+
|
173
|
+
@@connection_handlers ||= {}
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.connection_handlers=(handlers)
|
177
|
+
unless legacy_connection_handling
|
178
|
+
raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
|
179
|
+
end
|
180
|
+
|
181
|
+
@@connection_handlers = handlers
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns the symbol representing the current connected role.
|
185
|
+
#
|
186
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
187
|
+
# ActiveRecord::Base.current_role #=> :writing
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
191
|
+
# ActiveRecord::Base.current_role #=> :reading
|
192
|
+
# end
|
193
|
+
def self.current_role
|
194
|
+
if ActiveRecord::Base.legacy_connection_handling
|
195
|
+
connection_handlers.key(connection_handler) || default_role
|
196
|
+
else
|
197
|
+
connected_to_stack.reverse_each do |hash|
|
198
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
199
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(abstract_base_class)
|
200
|
+
end
|
201
|
+
|
202
|
+
default_role
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns the symbol representing the current connected shard.
|
207
|
+
#
|
208
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
209
|
+
# ActiveRecord::Base.current_shard #=> :default
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
# ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
|
213
|
+
# ActiveRecord::Base.current_shard #=> :one
|
214
|
+
# end
|
215
|
+
def self.current_shard
|
216
|
+
connected_to_stack.reverse_each do |hash|
|
217
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
218
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(abstract_base_class)
|
219
|
+
end
|
220
|
+
|
221
|
+
default_shard
|
222
|
+
end
|
223
|
+
|
224
|
+
# Returns the symbol representing the current setting for
|
225
|
+
# preventing writes.
|
226
|
+
#
|
227
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
228
|
+
# ActiveRecord::Base.current_preventing_writes #=> true
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
232
|
+
# ActiveRecord::Base.current_preventing_writes #=> false
|
233
|
+
# end
|
234
|
+
def self.current_preventing_writes
|
235
|
+
if legacy_connection_handling
|
236
|
+
connection_handler.prevent_writes
|
237
|
+
else
|
238
|
+
connected_to_stack.reverse_each do |hash|
|
239
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
240
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(abstract_base_class)
|
241
|
+
end
|
242
|
+
|
243
|
+
false
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.connected_to_stack # :nodoc:
|
248
|
+
if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
|
249
|
+
connected_to_stack
|
250
|
+
else
|
251
|
+
connected_to_stack = Concurrent::Array.new
|
252
|
+
Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
|
253
|
+
connected_to_stack
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def self.abstract_base_class # :nodoc:
|
258
|
+
klass = self
|
259
|
+
|
260
|
+
until klass == Base
|
261
|
+
break if klass.abstract_class?
|
262
|
+
klass = klass.superclass
|
263
|
+
end
|
264
|
+
|
265
|
+
klass
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.allow_unsafe_raw_sql # :nodoc:
|
269
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 6.2")
|
270
|
+
end
|
271
|
+
|
272
|
+
def self.allow_unsafe_raw_sql=(value) # :nodoc:
|
273
|
+
ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 6.2")
|
127
274
|
end
|
128
275
|
|
129
276
|
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
277
|
+
self.default_role = writing_role
|
278
|
+
self.default_shard = :default
|
279
|
+
|
280
|
+
def self.strict_loading_violation!(owner:, association:) # :nodoc:
|
281
|
+
case action_on_strict_loading_violation
|
282
|
+
when :raise
|
283
|
+
message = "`#{association}` called on `#{owner}` is marked for strict_loading and cannot be lazily loaded."
|
284
|
+
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
285
|
+
when :log
|
286
|
+
name = "strict_loading_violation.active_record"
|
287
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, association: association)
|
288
|
+
end
|
289
|
+
end
|
130
290
|
end
|
131
291
|
|
132
292
|
module ClassMethods
|
133
|
-
def allocate
|
134
|
-
define_attribute_methods
|
135
|
-
super
|
136
|
-
end
|
137
|
-
|
138
293
|
def initialize_find_by_cache # :nodoc:
|
139
|
-
@find_by_statement_cache = { true =>
|
294
|
+
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
140
295
|
end
|
141
296
|
|
142
297
|
def inherited(child_class) # :nodoc:
|
143
298
|
# initialize cache at class definition for thread safety
|
144
299
|
child_class.initialize_find_by_cache
|
300
|
+
unless child_class.base_class?
|
301
|
+
klass = self
|
302
|
+
until klass.base_class?
|
303
|
+
klass.initialize_find_by_cache
|
304
|
+
klass = klass.superclass
|
305
|
+
end
|
306
|
+
end
|
145
307
|
super
|
146
308
|
end
|
147
309
|
|
148
310
|
def find(*ids) # :nodoc:
|
149
311
|
# We don't have cache keys for this stuff yet
|
150
312
|
return super unless ids.length == 1
|
151
|
-
return super if block_given? ||
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
id = ids.first
|
158
|
-
if ActiveRecord::Base === id
|
159
|
-
id = id.id
|
160
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
161
|
-
You are passing an instance of ActiveRecord::Base to `find`.
|
162
|
-
Please pass the id of the object by calling `.id`.
|
163
|
-
MSG
|
164
|
-
end
|
313
|
+
return super if block_given? || primary_key.nil? || scope_attributes?
|
314
|
+
|
315
|
+
id = ids.first
|
316
|
+
|
317
|
+
return super if StatementCache.unsupported_value?(id)
|
165
318
|
|
166
319
|
key = primary_key
|
167
320
|
|
168
321
|
statement = cached_find_by_statement(key) { |params|
|
169
322
|
where(key => params.bind).limit(1)
|
170
323
|
}
|
171
|
-
|
172
|
-
|
173
|
-
raise
|
174
|
-
name, primary_key, id)
|
175
|
-
end
|
176
|
-
record
|
177
|
-
rescue RangeError
|
178
|
-
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
|
179
|
-
name, primary_key)
|
324
|
+
|
325
|
+
statement.execute([id], connection).first ||
|
326
|
+
raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
|
180
327
|
end
|
181
328
|
|
182
329
|
def find_by(*args) # :nodoc:
|
183
|
-
return super if scope_attributes?
|
330
|
+
return super if scope_attributes?
|
184
331
|
|
185
332
|
hash = args.first
|
333
|
+
return super unless Hash === hash
|
334
|
+
|
335
|
+
values = hash.values.map! { |value| value.respond_to?(:id) ? value.id : value }
|
336
|
+
return super if values.any? { |v| StatementCache.unsupported_value?(v) }
|
337
|
+
|
338
|
+
keys = hash.keys.map! do |key|
|
339
|
+
attribute_aliases[name = key.to_s] || begin
|
340
|
+
reflection = _reflect_on_association(name)
|
341
|
+
if reflection&.belongs_to? && !reflection.polymorphic?
|
342
|
+
reflection.join_foreign_key
|
343
|
+
elsif reflect_on_aggregation(name)
|
344
|
+
return super
|
345
|
+
else
|
346
|
+
name
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
186
350
|
|
187
|
-
return super
|
188
|
-
v.nil? || Array === v || Hash === v || Relation === v || Base === v
|
189
|
-
}
|
190
|
-
|
191
|
-
# We can't cache Post.find_by(author: david) ...yet
|
192
|
-
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
193
|
-
|
194
|
-
keys = hash.keys
|
351
|
+
return super unless keys.all? { |k| columns_hash.key?(k) }
|
195
352
|
|
196
353
|
statement = cached_find_by_statement(keys) { |params|
|
197
|
-
wheres = keys.
|
198
|
-
o[param] = params.bind
|
199
|
-
}
|
354
|
+
wheres = keys.index_with { params.bind }
|
200
355
|
where(wheres).limit(1)
|
201
356
|
}
|
357
|
+
|
202
358
|
begin
|
203
|
-
statement.execute(
|
359
|
+
statement.execute(values, connection).first
|
204
360
|
rescue TypeError
|
205
361
|
raise ActiveRecord::StatementInvalid
|
206
|
-
rescue RangeError
|
207
|
-
nil
|
208
362
|
end
|
209
363
|
end
|
210
364
|
|
211
365
|
def find_by!(*args) # :nodoc:
|
212
|
-
find_by(*args)
|
366
|
+
find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
|
213
367
|
end
|
214
368
|
|
215
369
|
def initialize_generated_modules # :nodoc:
|
216
370
|
generated_association_methods
|
217
371
|
end
|
218
372
|
|
219
|
-
def generated_association_methods
|
373
|
+
def generated_association_methods # :nodoc:
|
220
374
|
@generated_association_methods ||= begin
|
221
375
|
mod = const_set(:GeneratedAssociationMethods, Module.new)
|
376
|
+
private_constant :GeneratedAssociationMethods
|
222
377
|
include mod
|
378
|
+
|
223
379
|
mod
|
224
380
|
end
|
225
381
|
end
|
226
382
|
|
383
|
+
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
384
|
+
def filter_attributes
|
385
|
+
if defined?(@filter_attributes)
|
386
|
+
@filter_attributes
|
387
|
+
else
|
388
|
+
superclass.filter_attributes
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Specifies columns which shouldn't be exposed while calling +#inspect+.
|
393
|
+
attr_writer :filter_attributes
|
394
|
+
|
227
395
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
228
|
-
def inspect
|
396
|
+
def inspect # :nodoc:
|
229
397
|
if self == Base
|
230
398
|
super
|
231
399
|
elsif abstract_class?
|
@@ -233,41 +401,31 @@ module ActiveRecord
|
|
233
401
|
elsif !connected?
|
234
402
|
"#{super} (call '#{super}.connection' to establish a connection)"
|
235
403
|
elsif table_exists?
|
236
|
-
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } *
|
404
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
237
405
|
"#{super}(#{attr_list})"
|
238
406
|
else
|
239
407
|
"#{super}(Table doesn't exist)"
|
240
408
|
end
|
241
409
|
end
|
242
410
|
|
243
|
-
# Overwrite the default class equality method to provide support for
|
244
|
-
def ===(object)
|
411
|
+
# Overwrite the default class equality method to provide support for decorated models.
|
412
|
+
def ===(object) # :nodoc:
|
245
413
|
object.is_a?(self)
|
246
414
|
end
|
247
415
|
|
248
416
|
# Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
|
249
417
|
#
|
250
418
|
# class Post < ActiveRecord::Base
|
251
|
-
# scope :published_and_commented, -> { published.and(
|
419
|
+
# scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
|
252
420
|
# end
|
253
421
|
def arel_table # :nodoc:
|
254
|
-
@arel_table ||= Arel::Table.new(table_name,
|
255
|
-
end
|
256
|
-
|
257
|
-
# Returns the Arel engine.
|
258
|
-
def arel_engine # :nodoc:
|
259
|
-
@arel_engine ||=
|
260
|
-
if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
|
261
|
-
self
|
262
|
-
else
|
263
|
-
superclass.arel_engine
|
264
|
-
end
|
422
|
+
@arel_table ||= Arel::Table.new(table_name, klass: self)
|
265
423
|
end
|
266
424
|
|
267
425
|
def arel_attribute(name, table = arel_table) # :nodoc:
|
268
|
-
name = attribute_alias(name) if attribute_alias?(name)
|
269
426
|
table[name]
|
270
427
|
end
|
428
|
+
deprecate :arel_attribute
|
271
429
|
|
272
430
|
def predicate_builder # :nodoc:
|
273
431
|
@predicate_builder ||= PredicateBuilder.new(table_metadata)
|
@@ -277,28 +435,29 @@ module ActiveRecord
|
|
277
435
|
TypeCaster::Map.new(self)
|
278
436
|
end
|
279
437
|
|
280
|
-
|
438
|
+
def _internal? # :nodoc:
|
439
|
+
false
|
440
|
+
end
|
281
441
|
|
282
442
|
def cached_find_by_statement(key, &block) # :nodoc:
|
283
443
|
cache = @find_by_statement_cache[connection.prepared_statements]
|
284
|
-
cache
|
285
|
-
cache[key] ||= StatementCache.create(connection, &block)
|
286
|
-
}
|
444
|
+
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
287
445
|
end
|
288
446
|
|
289
|
-
|
290
|
-
relation
|
447
|
+
private
|
448
|
+
def relation
|
449
|
+
relation = Relation.create(self)
|
291
450
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
451
|
+
if finder_needs_type_condition? && !ignore_default_scope?
|
452
|
+
relation.where!(type_condition)
|
453
|
+
else
|
454
|
+
relation
|
455
|
+
end
|
296
456
|
end
|
297
|
-
end
|
298
457
|
|
299
|
-
|
300
|
-
|
301
|
-
|
458
|
+
def table_metadata
|
459
|
+
TableMetadata.new(self, arel_table)
|
460
|
+
end
|
302
461
|
end
|
303
462
|
|
304
463
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
@@ -310,7 +469,7 @@ module ActiveRecord
|
|
310
469
|
# # Instantiates a single new object
|
311
470
|
# User.new(first_name: 'Jamie')
|
312
471
|
def initialize(attributes = nil)
|
313
|
-
|
472
|
+
@new_record = true
|
314
473
|
@attributes = self.class._default_attributes.deep_dup
|
315
474
|
|
316
475
|
init_internals
|
@@ -336,15 +495,21 @@ module ActiveRecord
|
|
336
495
|
# post = Post.allocate
|
337
496
|
# post.init_with(coder)
|
338
497
|
# post.title # => 'hello world'
|
339
|
-
def init_with(coder)
|
498
|
+
def init_with(coder, &block)
|
340
499
|
coder = LegacyYamlAdapter.convert(self.class, coder)
|
341
|
-
|
342
|
-
|
343
|
-
|
500
|
+
attributes = self.class.yaml_encoder.decode(coder)
|
501
|
+
init_with_attributes(attributes, coder["new_record"], &block)
|
502
|
+
end
|
344
503
|
|
345
|
-
|
504
|
+
##
|
505
|
+
# Initialize an empty model object from +attributes+.
|
506
|
+
# +attributes+ should be an attributes object, and unlike the
|
507
|
+
# `initialize` method, no assignment calls are made per attribute.
|
508
|
+
def init_with_attributes(attributes, new_record = false) # :nodoc:
|
509
|
+
@new_record = new_record
|
510
|
+
@attributes = attributes
|
346
511
|
|
347
|
-
|
512
|
+
init_internals
|
348
513
|
|
349
514
|
yield self if block_given?
|
350
515
|
|
@@ -383,12 +548,14 @@ module ActiveRecord
|
|
383
548
|
##
|
384
549
|
def initialize_dup(other) # :nodoc:
|
385
550
|
@attributes = @attributes.deep_dup
|
386
|
-
@attributes.reset(
|
551
|
+
@attributes.reset(@primary_key)
|
387
552
|
|
388
553
|
_run_initialize_callbacks
|
389
554
|
|
390
|
-
@new_record
|
391
|
-
@
|
555
|
+
@new_record = true
|
556
|
+
@previously_new_record = false
|
557
|
+
@destroyed = false
|
558
|
+
@_start_transaction_state = nil
|
392
559
|
|
393
560
|
super
|
394
561
|
end
|
@@ -406,11 +573,9 @@ module ActiveRecord
|
|
406
573
|
# Post.new.encode_with(coder)
|
407
574
|
# coder # => {"attributes" => {"id" => nil, ... }}
|
408
575
|
def encode_with(coder)
|
409
|
-
|
410
|
-
coder[
|
411
|
-
coder[
|
412
|
-
coder['new_record'] = new_record?
|
413
|
-
coder['active_record_yaml_version'] = 1
|
576
|
+
self.class.yaml_encoder.encode(@attributes, coder)
|
577
|
+
coder["new_record"] = new_record?
|
578
|
+
coder["active_record_yaml_version"] = 2
|
414
579
|
end
|
415
580
|
|
416
581
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -434,7 +599,7 @@ module ActiveRecord
|
|
434
599
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
435
600
|
def hash
|
436
601
|
if id
|
437
|
-
id.hash
|
602
|
+
self.class.hash ^ id.hash
|
438
603
|
else
|
439
604
|
super
|
440
605
|
end
|
@@ -456,18 +621,41 @@ module ActiveRecord
|
|
456
621
|
# Allows sort on objects
|
457
622
|
def <=>(other_object)
|
458
623
|
if other_object.is_a?(self.class)
|
459
|
-
|
624
|
+
to_key <=> other_object.to_key
|
460
625
|
else
|
461
626
|
super
|
462
627
|
end
|
463
628
|
end
|
464
629
|
|
465
|
-
|
466
|
-
|
630
|
+
def present? # :nodoc:
|
631
|
+
true
|
632
|
+
end
|
633
|
+
|
634
|
+
def blank? # :nodoc:
|
635
|
+
false
|
636
|
+
end
|
637
|
+
|
638
|
+
# Returns +true+ if the record is read only.
|
467
639
|
def readonly?
|
468
640
|
@readonly
|
469
641
|
end
|
470
642
|
|
643
|
+
# Returns +true+ if the record is in strict_loading mode.
|
644
|
+
def strict_loading?
|
645
|
+
@strict_loading
|
646
|
+
end
|
647
|
+
|
648
|
+
# Sets the record to strict_loading mode. This will raise an error
|
649
|
+
# if the record tries to lazily load an association.
|
650
|
+
#
|
651
|
+
# user = User.first
|
652
|
+
# user.strict_loading!
|
653
|
+
# user.comments.to_a
|
654
|
+
# => ActiveRecord::StrictLoadingViolationError
|
655
|
+
def strict_loading!
|
656
|
+
@strict_loading = true
|
657
|
+
end
|
658
|
+
|
471
659
|
# Marks this record as read only.
|
472
660
|
def readonly!
|
473
661
|
@readonly = true
|
@@ -482,14 +670,15 @@ module ActiveRecord
|
|
482
670
|
# We check defined?(@attributes) not to issue warnings if the object is
|
483
671
|
# allocated but not initialized.
|
484
672
|
inspection = if defined?(@attributes) && @attributes
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
673
|
+
self.class.attribute_names.collect do |name|
|
674
|
+
if _has_attribute?(name)
|
675
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
676
|
+
end
|
677
|
+
end.compact.join(", ")
|
678
|
+
else
|
679
|
+
"not initialized"
|
680
|
+
end
|
681
|
+
|
493
682
|
"#<#{self.class} #{inspection}>"
|
494
683
|
end
|
495
684
|
|
@@ -499,65 +688,80 @@ module ActiveRecord
|
|
499
688
|
return super if custom_inspect_method_defined?
|
500
689
|
pp.object_address_group(self) do
|
501
690
|
if defined?(@attributes) && @attributes
|
502
|
-
|
503
|
-
pp.seplist(
|
504
|
-
|
505
|
-
pp.breakable ' '
|
691
|
+
attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
|
692
|
+
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
693
|
+
pp.breakable " "
|
506
694
|
pp.group(1) do
|
507
|
-
pp.text
|
508
|
-
pp.text
|
695
|
+
pp.text attr_name
|
696
|
+
pp.text ":"
|
509
697
|
pp.breakable
|
510
|
-
|
698
|
+
value = _read_attribute(attr_name)
|
699
|
+
value = inspection_filter.filter_param(attr_name, value) unless value.nil?
|
700
|
+
pp.pp value
|
511
701
|
end
|
512
702
|
end
|
513
703
|
else
|
514
|
-
pp.breakable
|
515
|
-
pp.text
|
704
|
+
pp.breakable " "
|
705
|
+
pp.text "not initialized"
|
516
706
|
end
|
517
707
|
end
|
518
708
|
end
|
519
709
|
|
520
710
|
# Returns a hash of the given methods with their names as keys and returned values as values.
|
521
711
|
def slice(*methods)
|
522
|
-
|
712
|
+
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
|
713
|
+
end
|
714
|
+
|
715
|
+
# Returns an array of the values returned by the given methods.
|
716
|
+
def values_at(*methods)
|
717
|
+
methods.flatten.map! { |method| public_send(method) }
|
523
718
|
end
|
524
719
|
|
525
720
|
private
|
721
|
+
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
|
722
|
+
# the array, and then rescues from the possible +NoMethodError+. If those elements are
|
723
|
+
# +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
|
724
|
+
# which significantly impacts upon performance.
|
725
|
+
#
|
726
|
+
# So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
|
727
|
+
#
|
728
|
+
# See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
|
729
|
+
def to_ary
|
730
|
+
nil
|
731
|
+
end
|
526
732
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
733
|
+
def init_internals
|
734
|
+
@primary_key = self.class.primary_key
|
735
|
+
@readonly = false
|
736
|
+
@previously_new_record = false
|
737
|
+
@destroyed = false
|
738
|
+
@marked_for_destruction = false
|
739
|
+
@destroyed_by_association = nil
|
740
|
+
@_start_transaction_state = nil
|
741
|
+
@strict_loading = self.class.strict_loading_by_default
|
742
|
+
|
743
|
+
self.class.define_attribute_methods
|
744
|
+
end
|
538
745
|
|
539
|
-
|
540
|
-
|
541
|
-
@destroyed = false
|
542
|
-
@marked_for_destruction = false
|
543
|
-
@destroyed_by_association = nil
|
544
|
-
@new_record = true
|
545
|
-
@txn = nil
|
546
|
-
@_start_transaction_state = {}
|
547
|
-
@transaction_state = nil
|
548
|
-
end
|
746
|
+
def initialize_internals_callback
|
747
|
+
end
|
549
748
|
|
550
|
-
|
551
|
-
|
749
|
+
def custom_inspect_method_defined?
|
750
|
+
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
751
|
+
end
|
552
752
|
|
553
|
-
|
554
|
-
|
555
|
-
|
753
|
+
class InspectionMask < DelegateClass(::String)
|
754
|
+
def pretty_print(pp)
|
755
|
+
pp.text __getobj__
|
756
|
+
end
|
556
757
|
end
|
557
|
-
|
758
|
+
private_constant :InspectionMask
|
558
759
|
|
559
|
-
|
560
|
-
|
561
|
-
|
760
|
+
def inspection_filter
|
761
|
+
@inspection_filter ||= begin
|
762
|
+
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
763
|
+
ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
|
764
|
+
end
|
765
|
+
end
|
562
766
|
end
|
563
767
|
end
|