activerecord 4.2.9 → 6.1.4.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 +5 -5
- data/CHANGELOG.md +964 -1382
- data/MIT-LICENSE +4 -2
- data/README.rdoc +15 -14
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +40 -15
- data/lib/active_record/associations/alias_tracker.rb +40 -43
- data/lib/active_record/associations/association.rb +162 -69
- data/lib/active_record/associations/association_scope.rb +105 -130
- data/lib/active_record/associations/belongs_to_association.rb +83 -65
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +57 -43
- data/lib/active_record/associations/builder/belongs_to.rb +74 -57
- data/lib/active_record/associations/builder/collection_association.rb +15 -37
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
- data/lib/active_record/associations/builder/has_many.rb +13 -5
- data/lib/active_record/associations/builder/has_one.rb +44 -6
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +148 -287
- data/lib/active_record/associations/collection_proxy.rb +252 -150
- data/lib/active_record/associations/foreign_association.rb +23 -1
- data/lib/active_record/associations/has_many_association.rb +56 -98
- data/lib/active_record/associations/has_many_through_association.rb +68 -89
- data/lib/active_record/associations/has_one_association.rb +73 -47
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
- 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 +174 -169
- data/lib/active_record/associations/preloader/association.rb +108 -115
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +97 -94
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +39 -19
- data/lib/active_record/associations.rb +1845 -1598
- data/lib/active_record/attribute_assignment.rb +59 -185
- data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
- data/lib/active_record/attribute_methods/dirty.rb +168 -148
- data/lib/active_record/attribute_methods/primary_key.rb +93 -83
- data/lib/active_record/attribute_methods/query.rb +8 -10
- data/lib/active_record/attribute_methods/read.rb +19 -79
- data/lib/active_record/attribute_methods/serialization.rb +49 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
- data/lib/active_record/attribute_methods/write.rb +24 -55
- data/lib/active_record/attribute_methods.rb +149 -154
- data/lib/active_record/attributes.rb +234 -78
- data/lib/active_record/autosave_association.rb +133 -60
- data/lib/active_record/base.rb +46 -46
- data/lib/active_record/callbacks.rb +234 -79
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
- data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
- data/lib/active_record/connection_adapters/column.rb +67 -40
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +496 -298
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
- data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +314 -41
- data/lib/active_record/core.rb +458 -241
- data/lib/active_record/counter_cache.rb +70 -49
- 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/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +211 -92
- data/lib/active_record/errors.rb +224 -54
- data/lib/active_record/explain.rb +27 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +33 -14
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +275 -500
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +175 -110
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +121 -29
- data/lib/active_record/internal_metadata.rb +62 -0
- data/lib/active_record/legacy_yaml_adapter.rb +27 -5
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +98 -92
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +93 -31
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +185 -90
- data/lib/active_record/migration/compatibility.rb +295 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +673 -325
- data/lib/active_record/model_schema.rb +418 -113
- data/lib/active_record/nested_attributes.rb +263 -224
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +572 -136
- data/lib/active_record/query_cache.rb +29 -23
- data/lib/active_record/querying.rb +50 -31
- data/lib/active_record/railtie.rb +170 -51
- data/lib/active_record/railties/console_sandbox.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +523 -199
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +454 -291
- data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
- data/lib/active_record/relation/batches.rb +217 -59
- data/lib/active_record/relation/calculations.rb +324 -249
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +316 -242
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +95 -103
- data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +136 -122
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +757 -413
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -20
- data/lib/active_record/relation/where_clause.rb +239 -0
- data/lib/active_record/relation.rb +554 -343
- data/lib/active_record/result.rb +91 -47
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +134 -122
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +141 -92
- data/lib/active_record/schema_migration.rb +24 -23
- data/lib/active_record/scoping/default.rb +96 -83
- data/lib/active_record/scoping/named.rb +78 -36
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +48 -0
- data/lib/active_record/serialization.rb +8 -6
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +89 -36
- data/lib/active_record/store.rb +128 -43
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +81 -0
- data/lib/active_record/tasks/database_tasks.rb +364 -130
- data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
- data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +86 -43
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +182 -163
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +27 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +21 -16
- data/lib/active_record/type/type_map.rb +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +84 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +12 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +63 -56
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -29
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
- data/lib/rails/generators/active_record/migration.rb +35 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +172 -65
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_decorators.rb +0 -66
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,10 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "yaml"
|
5
|
+
require "zlib"
|
6
|
+
require "set"
|
7
|
+
require "active_support/dependencies"
|
8
|
+
require "active_support/core_ext/digest/uuid"
|
9
|
+
require "active_record/fixture_set/file"
|
10
|
+
require "active_record/fixture_set/render_context"
|
11
|
+
require "active_record/fixture_set/table_rows"
|
12
|
+
require "active_record/test_fixtures"
|
8
13
|
|
9
14
|
module ActiveRecord
|
10
15
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
@@ -35,7 +40,7 @@ module ActiveRecord
|
|
35
40
|
# separated by a blank line for your viewing pleasure.
|
36
41
|
#
|
37
42
|
# Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
|
38
|
-
# See
|
43
|
+
# See https://yaml.org/type/omap.html
|
39
44
|
# for the specification. You will need ordered fixtures when you have foreign key constraints
|
40
45
|
# on keys in the same table. This is commonly needed for tree structures. Example:
|
41
46
|
#
|
@@ -54,7 +59,7 @@ module ActiveRecord
|
|
54
59
|
# Since fixtures are a testing construct, we use them in our unit and functional tests. There
|
55
60
|
# are two ways to use the fixtures, but first let's take a look at a sample unit test:
|
56
61
|
#
|
57
|
-
# require
|
62
|
+
# require "test_helper"
|
58
63
|
#
|
59
64
|
# class WebSiteTest < ActiveSupport::TestCase
|
60
65
|
# test "web_site_count" do
|
@@ -65,17 +70,36 @@ module ActiveRecord
|
|
65
70
|
# By default, +test_helper.rb+ will load all of your fixtures into your test
|
66
71
|
# database, so this test will succeed.
|
67
72
|
#
|
68
|
-
# The testing environment will automatically load the
|
73
|
+
# The testing environment will automatically load all the fixtures into the database before each
|
69
74
|
# test. To ensure consistent data, the environment deletes the fixtures before running the load.
|
70
75
|
#
|
71
76
|
# In addition to being available in the database, the fixture's data may also be accessed by
|
72
|
-
# using a special dynamic method, which has the same name as the model
|
73
|
-
# name of the fixture to instantiate:
|
77
|
+
# using a special dynamic method, which has the same name as the model.
|
74
78
|
#
|
75
|
-
#
|
79
|
+
# Passing in a fixture name to this dynamic method returns the fixture matching this name:
|
80
|
+
#
|
81
|
+
# test "find one" do
|
76
82
|
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
77
83
|
# end
|
78
84
|
#
|
85
|
+
# Passing in multiple fixture names returns all fixtures matching these names:
|
86
|
+
#
|
87
|
+
# test "find all by name" do
|
88
|
+
# assert_equal 2, web_sites(:rubyonrails, :google).length
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# Passing in no arguments returns all fixtures:
|
92
|
+
#
|
93
|
+
# test "find all" do
|
94
|
+
# assert_equal 2, web_sites.length
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# Passing in any fixture name that does not exist will raise <tt>StandardError</tt>:
|
98
|
+
#
|
99
|
+
# test "find by name that does not exist" do
|
100
|
+
# assert_raise(StandardError) { web_sites(:reddit) }
|
101
|
+
# end
|
102
|
+
#
|
79
103
|
# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
|
80
104
|
# following tests:
|
81
105
|
#
|
@@ -87,8 +111,8 @@ module ActiveRecord
|
|
87
111
|
# assert_equal "Ruby on Rails", @rubyonrails.name
|
88
112
|
# end
|
89
113
|
#
|
90
|
-
# In order to use these methods to access fixtured data within your
|
91
|
-
# following in your
|
114
|
+
# In order to use these methods to access fixtured data within your test cases, you must specify one of the
|
115
|
+
# following in your ActiveSupport::TestCase-derived class:
|
92
116
|
#
|
93
117
|
# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
|
94
118
|
# self.use_instantiated_fixtures = true
|
@@ -102,14 +126,14 @@ module ActiveRecord
|
|
102
126
|
#
|
103
127
|
# = Dynamic fixtures with ERB
|
104
128
|
#
|
105
|
-
#
|
129
|
+
# Sometimes you don't care about the content of the fixtures as much as you care about the volume.
|
106
130
|
# In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
|
107
131
|
# testing, like:
|
108
132
|
#
|
109
133
|
# <% 1.upto(1000) do |i| %>
|
110
134
|
# fix_<%= i %>:
|
111
135
|
# id: <%= i %>
|
112
|
-
# name: guy_<%=
|
136
|
+
# name: guy_<%= i %>
|
113
137
|
# <% end %>
|
114
138
|
#
|
115
139
|
# This will create 1000 very simple fixtures.
|
@@ -123,49 +147,49 @@ module ActiveRecord
|
|
123
147
|
#
|
124
148
|
# Helper methods defined in a fixture will not be available in other fixtures, to prevent against
|
125
149
|
# unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
|
126
|
-
# that is included in
|
150
|
+
# that is included in ActiveRecord::FixtureSet.context_class.
|
127
151
|
#
|
128
|
-
# - define a helper method in
|
152
|
+
# - define a helper method in <tt>test_helper.rb</tt>
|
129
153
|
# module FixtureFileHelpers
|
130
154
|
# def file_sha(path)
|
131
155
|
# Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
|
132
156
|
# end
|
133
157
|
# end
|
134
|
-
# ActiveRecord::FixtureSet.context_class.
|
158
|
+
# ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
|
135
159
|
#
|
136
160
|
# - use the helper method in a fixture
|
137
161
|
# photo:
|
138
162
|
# name: kitten.png
|
139
163
|
# sha: <%= file_sha 'files/kitten.png' %>
|
140
164
|
#
|
141
|
-
# = Transactional
|
165
|
+
# = Transactional Tests
|
142
166
|
#
|
143
167
|
# Test cases can use begin+rollback to isolate their changes to the database instead of having to
|
144
168
|
# delete+insert for every test case.
|
145
169
|
#
|
146
170
|
# class FooTest < ActiveSupport::TestCase
|
147
|
-
# self.
|
171
|
+
# self.use_transactional_tests = true
|
148
172
|
#
|
149
173
|
# test "godzilla" do
|
150
|
-
#
|
174
|
+
# assert_not_empty Foo.all
|
151
175
|
# Foo.destroy_all
|
152
|
-
#
|
176
|
+
# assert_empty Foo.all
|
153
177
|
# end
|
154
178
|
#
|
155
179
|
# test "godzilla aftermath" do
|
156
|
-
#
|
180
|
+
# assert_not_empty Foo.all
|
157
181
|
# end
|
158
182
|
# end
|
159
183
|
#
|
160
|
-
# If you preload your test database with all fixture data (probably
|
161
|
-
# transactional
|
184
|
+
# If you preload your test database with all fixture data (probably by running <tt>bin/rails db:fixtures:load</tt>)
|
185
|
+
# and use transactional tests, then you may omit all fixtures declarations in your test cases since
|
162
186
|
# all the data's already there and every case rolls back its changes.
|
163
187
|
#
|
164
188
|
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
|
165
189
|
# true. This will provide access to fixture data for every table that has been loaded through
|
166
190
|
# fixtures (depending on the value of +use_instantiated_fixtures+).
|
167
191
|
#
|
168
|
-
# When *not* to use transactional
|
192
|
+
# When *not* to use transactional tests:
|
169
193
|
#
|
170
194
|
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
|
171
195
|
# all parent transactions commit, particularly, the fixtures transaction which is begun in setup
|
@@ -394,207 +418,256 @@ module ActiveRecord
|
|
394
418
|
# <<: *DEFAULTS
|
395
419
|
#
|
396
420
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
421
|
+
#
|
422
|
+
# Besides using "DEFAULTS", you can also specify what fixtures will
|
423
|
+
# be ignored by setting "ignore" in "_fixture" section.
|
424
|
+
#
|
425
|
+
# # users.yml
|
426
|
+
# _fixture:
|
427
|
+
# ignore:
|
428
|
+
# - base
|
429
|
+
# # or use "ignore: base" when there is only one fixture needs to be ignored.
|
430
|
+
#
|
431
|
+
# base: &base
|
432
|
+
# admin: false
|
433
|
+
# introduction: "This is a default description"
|
434
|
+
#
|
435
|
+
# admin:
|
436
|
+
# <<: *base
|
437
|
+
# admin: true
|
438
|
+
#
|
439
|
+
# visitor:
|
440
|
+
# <<: *base
|
441
|
+
#
|
442
|
+
# In the above example, 'base' will be ignored when creating fixtures.
|
443
|
+
# This can be used for common attributes inheriting.
|
444
|
+
#
|
445
|
+
# == Configure the fixture model class
|
446
|
+
#
|
447
|
+
# It's possible to set the fixture's model class directly in the YAML file.
|
448
|
+
# This is helpful when fixtures are loaded outside tests and
|
449
|
+
# +set_fixture_class+ is not available (e.g.
|
450
|
+
# when running <tt>bin/rails db:fixtures:load</tt>).
|
451
|
+
#
|
452
|
+
# _fixture:
|
453
|
+
# model_class: User
|
454
|
+
# david:
|
455
|
+
# name: David
|
456
|
+
#
|
457
|
+
# Any fixtures labeled "_fixture" are safely ignored.
|
397
458
|
class FixtureSet
|
398
459
|
#--
|
399
460
|
# An instance of FixtureSet is normally stored in a single YAML file and
|
400
461
|
# possibly in a folder with the same name.
|
401
462
|
#++
|
402
463
|
|
403
|
-
MAX_ID = 2
|
464
|
+
MAX_ID = 2**30 - 1
|
404
465
|
|
405
|
-
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
|
466
|
+
@@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
|
406
467
|
|
407
|
-
|
408
|
-
config.pluralize_table_names ?
|
409
|
-
fixture_set_name.singularize.camelize :
|
410
|
-
fixture_set_name.camelize
|
411
|
-
end
|
468
|
+
cattr_accessor :all_loaded_fixtures, default: {}
|
412
469
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
end
|
470
|
+
class ClassCache
|
471
|
+
def initialize(class_names, config)
|
472
|
+
@class_names = class_names.stringify_keys
|
473
|
+
@config = config
|
418
474
|
|
419
|
-
|
420
|
-
|
421
|
-
|
475
|
+
# Remove string values that aren't constants or subclasses of AR
|
476
|
+
@class_names.delete_if do |klass_name, klass|
|
477
|
+
!insert_class(@class_names, klass_name, klass)
|
478
|
+
end
|
479
|
+
end
|
422
480
|
|
423
|
-
|
424
|
-
|
425
|
-
|
481
|
+
def [](fs_name)
|
482
|
+
@class_names.fetch(fs_name) do
|
483
|
+
klass = default_fixture_model(fs_name, @config).safe_constantize
|
484
|
+
insert_class(@class_names, fs_name, klass)
|
485
|
+
end
|
486
|
+
end
|
426
487
|
|
427
|
-
|
428
|
-
|
488
|
+
private
|
489
|
+
def insert_class(class_names, name, klass)
|
490
|
+
# We only want to deal with AR objects.
|
491
|
+
if klass && klass < ActiveRecord::Base
|
492
|
+
class_names[name] = klass
|
493
|
+
else
|
494
|
+
class_names[name] = nil
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def default_fixture_model(fs_name, config)
|
499
|
+
ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
|
500
|
+
end
|
429
501
|
end
|
430
502
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
503
|
+
class << self
|
504
|
+
def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
505
|
+
config.pluralize_table_names ?
|
506
|
+
fixture_set_name.singularize.camelize :
|
507
|
+
fixture_set_name.camelize
|
436
508
|
end
|
437
|
-
end
|
438
509
|
|
439
|
-
|
440
|
-
|
441
|
-
|
510
|
+
def default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
511
|
+
"#{ config.table_name_prefix }"\
|
512
|
+
"#{ fixture_set_name.tr('/', '_') }"\
|
513
|
+
"#{ config.table_name_suffix }".to_sym
|
514
|
+
end
|
442
515
|
|
443
|
-
|
444
|
-
|
445
|
-
fixture_set.each do |fixture_name, fixture|
|
446
|
-
begin
|
447
|
-
object.instance_variable_set "@#{fixture_name}", fixture.find
|
448
|
-
rescue FixtureClassNotFound
|
449
|
-
nil
|
450
|
-
end
|
451
|
-
end
|
516
|
+
def reset_cache
|
517
|
+
@@all_cached_fixtures.clear
|
452
518
|
end
|
453
|
-
end
|
454
519
|
|
455
|
-
|
456
|
-
|
457
|
-
instantiate_fixtures(object, fixture_set, load_instances)
|
520
|
+
def cache_for_connection(connection)
|
521
|
+
@@all_cached_fixtures[connection]
|
458
522
|
end
|
459
|
-
end
|
460
523
|
|
461
|
-
|
462
|
-
|
524
|
+
def fixture_is_cached?(connection, table_name)
|
525
|
+
cache_for_connection(connection)[table_name]
|
526
|
+
end
|
463
527
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
528
|
+
def cached_fixtures(connection, keys_to_fetch = nil)
|
529
|
+
if keys_to_fetch
|
530
|
+
cache_for_connection(connection).values_at(*keys_to_fetch)
|
531
|
+
else
|
532
|
+
cache_for_connection(connection).values
|
533
|
+
end
|
534
|
+
end
|
468
535
|
|
469
|
-
|
470
|
-
|
536
|
+
def cache_fixtures(connection, fixtures_map)
|
537
|
+
cache_for_connection(connection).update(fixtures_map)
|
471
538
|
end
|
472
539
|
|
473
|
-
def
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
540
|
+
def instantiate_fixtures(object, fixture_set, load_instances = true)
|
541
|
+
return unless load_instances
|
542
|
+
fixture_set.each do |fixture_name, fixture|
|
543
|
+
object.instance_variable_set "@#{fixture_name}", fixture.find
|
544
|
+
rescue FixtureClassNotFound
|
545
|
+
nil
|
546
|
+
end
|
478
547
|
end
|
479
548
|
|
480
|
-
|
549
|
+
def instantiate_all_loaded_fixtures(object, load_instances = true)
|
550
|
+
all_loaded_fixtures.each_value do |fixture_set|
|
551
|
+
instantiate_fixtures(object, fixture_set, load_instances)
|
552
|
+
end
|
553
|
+
end
|
481
554
|
|
482
|
-
def
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
555
|
+
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
|
556
|
+
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
557
|
+
class_names = ClassCache.new class_names, config
|
558
|
+
|
559
|
+
# FIXME: Apparently JK uses this.
|
560
|
+
connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
|
561
|
+
|
562
|
+
fixture_files_to_read = fixture_set_names.reject do |fs_name|
|
563
|
+
fixture_is_cached?(connection.call, fs_name)
|
488
564
|
end
|
565
|
+
|
566
|
+
if fixture_files_to_read.any?
|
567
|
+
fixtures_map = read_and_insert(
|
568
|
+
fixtures_directory,
|
569
|
+
fixture_files_to_read,
|
570
|
+
class_names,
|
571
|
+
connection,
|
572
|
+
)
|
573
|
+
cache_fixtures(connection.call, fixtures_map)
|
574
|
+
end
|
575
|
+
cached_fixtures(connection.call, fixture_set_names)
|
489
576
|
end
|
490
577
|
|
491
|
-
|
492
|
-
|
578
|
+
# Returns a consistent, platform-independent identifier for +label+.
|
579
|
+
# Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
|
580
|
+
def identify(label, column_type = :integer)
|
581
|
+
if column_type == :uuid
|
582
|
+
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
|
583
|
+
else
|
584
|
+
Zlib.crc32(label.to_s) % MAX_ID
|
585
|
+
end
|
493
586
|
end
|
494
|
-
end
|
495
587
|
|
496
|
-
|
497
|
-
|
498
|
-
|
588
|
+
def signed_global_id(fixture_set_name, label, column_type: :integer, **options)
|
589
|
+
identifier = identify(label, column_type)
|
590
|
+
model_name = default_fixture_model_name(fixture_set_name)
|
591
|
+
uri = URI::GID.build([GlobalID.app, model_name, identifier, {}])
|
499
592
|
|
500
|
-
|
501
|
-
|
593
|
+
SignedGlobalID.new(uri, **options)
|
594
|
+
end
|
502
595
|
|
503
|
-
|
504
|
-
|
505
|
-
|
596
|
+
# Superclass for the evaluation contexts used by ERB fixtures.
|
597
|
+
def context_class
|
598
|
+
@context_class ||= Class.new
|
599
|
+
end
|
506
600
|
|
507
|
-
|
508
|
-
connection
|
601
|
+
private
|
602
|
+
def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
|
509
603
|
fixtures_map = {}
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
conn,
|
516
|
-
fs_name,
|
604
|
+
fixture_sets = fixture_files.map do |fixture_set_name|
|
605
|
+
klass = class_names[fixture_set_name]
|
606
|
+
fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
|
607
|
+
nil,
|
608
|
+
fixture_set_name,
|
517
609
|
klass,
|
518
|
-
::File.join(fixtures_directory,
|
610
|
+
::File.join(fixtures_directory, fixture_set_name)
|
611
|
+
)
|
519
612
|
end
|
613
|
+
update_all_loaded_fixtures(fixtures_map)
|
520
614
|
|
521
|
-
|
615
|
+
insert(fixture_sets, connection)
|
522
616
|
|
523
|
-
|
524
|
-
|
525
|
-
conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
|
526
|
-
table_rows = fs.table_rows
|
617
|
+
fixtures_map
|
618
|
+
end
|
527
619
|
|
528
|
-
|
529
|
-
|
530
|
-
|
620
|
+
def insert(fixture_sets, connection) # :nodoc:
|
621
|
+
fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
|
622
|
+
if fixture_set.model_class
|
623
|
+
fixture_set.model_class.connection
|
624
|
+
else
|
625
|
+
connection.call
|
626
|
+
end
|
627
|
+
end
|
531
628
|
|
532
|
-
|
533
|
-
|
534
|
-
conn.insert_fixture(row, fixture_set_name)
|
535
|
-
end
|
536
|
-
end
|
629
|
+
fixture_sets_by_connection.each do |conn, set|
|
630
|
+
table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
|
537
631
|
|
538
|
-
|
539
|
-
|
540
|
-
|
632
|
+
set.each do |fixture_set|
|
633
|
+
fixture_set.table_rows.each do |table, rows|
|
634
|
+
table_rows_for_connection[table].unshift(*rows)
|
541
635
|
end
|
542
636
|
end
|
543
|
-
end
|
544
637
|
|
545
|
-
|
546
|
-
end
|
547
|
-
end
|
548
|
-
cached_fixtures(connection, fixture_set_names)
|
549
|
-
end
|
550
|
-
|
551
|
-
# Returns a consistent, platform-independent identifier for +label+.
|
552
|
-
# Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
|
553
|
-
def self.identify(label, column_type = :integer)
|
554
|
-
if column_type == :uuid
|
555
|
-
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
|
556
|
-
else
|
557
|
-
Zlib.crc32(label.to_s) % MAX_ID
|
558
|
-
end
|
559
|
-
end
|
638
|
+
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
560
639
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
640
|
+
# Cap primary key sequences to max(pk).
|
641
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
642
|
+
set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
|
643
|
+
end
|
644
|
+
end
|
645
|
+
end
|
565
646
|
|
566
|
-
|
567
|
-
|
647
|
+
def update_all_loaded_fixtures(fixtures_map) # :nodoc:
|
648
|
+
all_loaded_fixtures.update(fixtures_map)
|
649
|
+
end
|
568
650
|
end
|
569
651
|
|
570
|
-
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
652
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
|
571
653
|
|
572
|
-
def initialize(
|
654
|
+
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
|
573
655
|
@name = name
|
574
656
|
@path = path
|
575
657
|
@config = config
|
576
|
-
@model_class = nil
|
577
658
|
|
578
|
-
|
579
|
-
@model_class = class_name
|
580
|
-
else
|
581
|
-
@model_class = class_name.safe_constantize if class_name
|
582
|
-
end
|
659
|
+
self.model_class = class_name
|
583
660
|
|
584
|
-
@
|
661
|
+
@fixtures = read_fixture_files(path)
|
585
662
|
|
586
|
-
@table_name =
|
587
|
-
model_class.table_name :
|
588
|
-
self.class.default_fixture_table_name(name, config) )
|
589
|
-
|
590
|
-
@fixtures = read_fixture_files path, @model_class
|
663
|
+
@table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
|
591
664
|
end
|
592
665
|
|
593
666
|
def [](x)
|
594
667
|
fixtures[x]
|
595
668
|
end
|
596
669
|
|
597
|
-
def []=(k,v)
|
670
|
+
def []=(k, v)
|
598
671
|
fixtures[k] = v
|
599
672
|
end
|
600
673
|
|
@@ -609,154 +682,53 @@ module ActiveRecord
|
|
609
682
|
# Returns a hash of rows to be inserted. The key is the table, the value is
|
610
683
|
# a list of rows to insert to that table.
|
611
684
|
def table_rows
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
# allow a standard key to be used for doing defaults in YAML
|
616
|
-
fixtures.delete('DEFAULTS')
|
617
|
-
|
618
|
-
# track any join tables we need to insert later
|
619
|
-
rows = Hash.new { |h,table| h[table] = [] }
|
620
|
-
|
621
|
-
rows[table_name] = fixtures.map do |label, fixture|
|
622
|
-
row = fixture.to_hash
|
623
|
-
|
624
|
-
if model_class
|
625
|
-
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
|
626
|
-
if model_class.record_timestamps
|
627
|
-
timestamp_column_names.each do |c_name|
|
628
|
-
row[c_name] = now unless row.key?(c_name)
|
629
|
-
end
|
630
|
-
end
|
685
|
+
# allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
|
686
|
+
fixtures.except!(*ignored_fixtures)
|
631
687
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
if has_primary_key_column? && !row.include?(primary_key_name)
|
639
|
-
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
|
640
|
-
end
|
641
|
-
|
642
|
-
# If STI is used, find the correct subclass for association reflection
|
643
|
-
reflection_class =
|
644
|
-
if row.include?(inheritance_column_name)
|
645
|
-
row[inheritance_column_name].constantize rescue model_class
|
646
|
-
else
|
647
|
-
model_class
|
648
|
-
end
|
649
|
-
|
650
|
-
reflection_class._reflections.each_value do |association|
|
651
|
-
case association.macro
|
652
|
-
when :belongs_to
|
653
|
-
# Do not replace association name with association foreign key if they are named the same
|
654
|
-
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
655
|
-
|
656
|
-
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
657
|
-
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
658
|
-
# support polymorphic belongs_to as "label (Type)"
|
659
|
-
row[association.foreign_type] = $1
|
660
|
-
end
|
661
|
-
|
662
|
-
fk_type = reflection_class.columns_hash[fk_name].type
|
663
|
-
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
664
|
-
end
|
665
|
-
when :has_many
|
666
|
-
if association.options[:through]
|
667
|
-
add_join_records(rows, row, HasManyThroughProxy.new(association))
|
668
|
-
end
|
669
|
-
end
|
670
|
-
end
|
671
|
-
end
|
672
|
-
|
673
|
-
row
|
674
|
-
end
|
675
|
-
rows
|
676
|
-
end
|
677
|
-
|
678
|
-
class ReflectionProxy # :nodoc:
|
679
|
-
def initialize(association)
|
680
|
-
@association = association
|
681
|
-
end
|
682
|
-
|
683
|
-
def join_table
|
684
|
-
@association.join_table
|
685
|
-
end
|
686
|
-
|
687
|
-
def name
|
688
|
-
@association.name
|
689
|
-
end
|
690
|
-
|
691
|
-
def primary_key_type
|
692
|
-
@association.klass.column_types[@association.klass.primary_key].type
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
|
-
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
697
|
-
def rhs_key
|
698
|
-
@association.foreign_key
|
699
|
-
end
|
700
|
-
|
701
|
-
def lhs_key
|
702
|
-
@association.through_reflection.foreign_key
|
703
|
-
end
|
704
|
-
|
705
|
-
def join_table
|
706
|
-
@association.through_reflection.table_name
|
707
|
-
end
|
688
|
+
TableRows.new(
|
689
|
+
table_name,
|
690
|
+
model_class: model_class,
|
691
|
+
fixtures: fixtures,
|
692
|
+
config: config,
|
693
|
+
).to_hash
|
708
694
|
end
|
709
695
|
|
710
696
|
private
|
711
|
-
def
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
@primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
|
717
|
-
end
|
718
|
-
|
719
|
-
def add_join_records(rows, row, association)
|
720
|
-
# This is the case when the join table has no fixtures file
|
721
|
-
if (targets = row.delete(association.name.to_s))
|
722
|
-
table_name = association.join_table
|
723
|
-
column_type = association.primary_key_type
|
724
|
-
lhs_key = association.lhs_key
|
725
|
-
rhs_key = association.rhs_key
|
726
|
-
|
727
|
-
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
728
|
-
rows[table_name].concat targets.map { |target|
|
729
|
-
{ lhs_key => row[primary_key_name],
|
730
|
-
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
731
|
-
}
|
697
|
+
def model_class=(class_name)
|
698
|
+
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
699
|
+
@model_class = class_name
|
700
|
+
else
|
701
|
+
@model_class = class_name.safe_constantize if class_name
|
732
702
|
end
|
733
703
|
end
|
734
704
|
|
735
|
-
def
|
736
|
-
@
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
def inheritance_column_name
|
746
|
-
@inheritance_column_name ||= model_class && model_class.inheritance_column
|
747
|
-
end
|
705
|
+
def ignored_fixtures=(base)
|
706
|
+
@ignored_fixtures =
|
707
|
+
case base
|
708
|
+
when Array
|
709
|
+
base
|
710
|
+
when String
|
711
|
+
[base]
|
712
|
+
else
|
713
|
+
[]
|
714
|
+
end
|
748
715
|
|
749
|
-
|
750
|
-
@
|
716
|
+
@ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
|
717
|
+
@ignored_fixtures.compact
|
751
718
|
end
|
752
719
|
|
753
|
-
|
720
|
+
# Loads the fixtures from the YAML file at +path+.
|
721
|
+
# If the file sets the +model_class+ and current instance value is not set,
|
722
|
+
# it uses the file value.
|
723
|
+
def read_fixture_files(path)
|
754
724
|
yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
|
755
725
|
::File.file?(f)
|
756
726
|
} + [yaml_file_path(path)]
|
757
727
|
|
758
728
|
yaml_files.each_with_object({}) do |file, fixtures|
|
759
729
|
FixtureSet::File.open(file) do |fh|
|
730
|
+
self.model_class ||= fh.model_class if fh.model_class
|
731
|
+
self.ignored_fixtures ||= fh.ignored_fixtures
|
760
732
|
fh.each do |fixture_name, row|
|
761
733
|
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
762
734
|
end
|
@@ -767,15 +739,8 @@ module ActiveRecord
|
|
767
739
|
def yaml_file_path(path)
|
768
740
|
"#{path}.yml"
|
769
741
|
end
|
770
|
-
|
771
742
|
end
|
772
743
|
|
773
|
-
#--
|
774
|
-
# Deprecate 'Fixtures' in favor of 'FixtureSet'.
|
775
|
-
#++
|
776
|
-
# :nodoc:
|
777
|
-
Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
|
778
|
-
|
779
744
|
class Fixture #:nodoc:
|
780
745
|
include Enumerable
|
781
746
|
|
@@ -807,203 +772,13 @@ module ActiveRecord
|
|
807
772
|
alias :to_hash :fixture
|
808
773
|
|
809
774
|
def find
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
end
|
814
|
-
else
|
815
|
-
raise FixtureClassNotFound, "No class attached to find."
|
816
|
-
end
|
817
|
-
end
|
818
|
-
end
|
819
|
-
end
|
820
|
-
|
821
|
-
module ActiveRecord
|
822
|
-
module TestFixtures
|
823
|
-
extend ActiveSupport::Concern
|
824
|
-
|
825
|
-
def before_setup
|
826
|
-
setup_fixtures
|
827
|
-
super
|
828
|
-
end
|
829
|
-
|
830
|
-
def after_teardown
|
831
|
-
super
|
832
|
-
teardown_fixtures
|
833
|
-
end
|
834
|
-
|
835
|
-
included do
|
836
|
-
class_attribute :fixture_path, :instance_writer => false
|
837
|
-
class_attribute :fixture_table_names
|
838
|
-
class_attribute :fixture_class_names
|
839
|
-
class_attribute :use_transactional_fixtures
|
840
|
-
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
|
841
|
-
class_attribute :pre_loaded_fixtures
|
842
|
-
class_attribute :config
|
843
|
-
|
844
|
-
self.fixture_table_names = []
|
845
|
-
self.use_transactional_fixtures = true
|
846
|
-
self.use_instantiated_fixtures = false
|
847
|
-
self.pre_loaded_fixtures = false
|
848
|
-
self.config = ActiveRecord::Base
|
849
|
-
|
850
|
-
self.fixture_class_names = Hash.new do |h, fixture_set_name|
|
851
|
-
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name, self.config)
|
852
|
-
end
|
853
|
-
end
|
854
|
-
|
855
|
-
module ClassMethods
|
856
|
-
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
857
|
-
#
|
858
|
-
# Examples:
|
859
|
-
#
|
860
|
-
# set_fixture_class some_fixture: SomeModel,
|
861
|
-
# 'namespaced/fixture' => Another::Model
|
862
|
-
#
|
863
|
-
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
864
|
-
def set_fixture_class(class_names = {})
|
865
|
-
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
|
866
|
-
end
|
867
|
-
|
868
|
-
def fixtures(*fixture_set_names)
|
869
|
-
if fixture_set_names.first == :all
|
870
|
-
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
|
871
|
-
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
872
|
-
else
|
873
|
-
fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
|
874
|
-
end
|
875
|
-
|
876
|
-
self.fixture_table_names |= fixture_set_names
|
877
|
-
setup_fixture_accessors(fixture_set_names)
|
878
|
-
end
|
879
|
-
|
880
|
-
def setup_fixture_accessors(fixture_set_names = nil)
|
881
|
-
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
882
|
-
methods = Module.new do
|
883
|
-
fixture_set_names.each do |fs_name|
|
884
|
-
fs_name = fs_name.to_s
|
885
|
-
accessor_name = fs_name.tr('/', '_').to_sym
|
886
|
-
|
887
|
-
define_method(accessor_name) do |*fixture_names|
|
888
|
-
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
889
|
-
|
890
|
-
@fixture_cache[fs_name] ||= {}
|
891
|
-
|
892
|
-
instances = fixture_names.map do |f_name|
|
893
|
-
f_name = f_name.to_s
|
894
|
-
@fixture_cache[fs_name].delete(f_name) if force_reload
|
895
|
-
|
896
|
-
if @loaded_fixtures[fs_name][f_name]
|
897
|
-
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
898
|
-
else
|
899
|
-
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
900
|
-
end
|
901
|
-
end
|
902
|
-
|
903
|
-
instances.size == 1 ? instances.first : instances
|
904
|
-
end
|
905
|
-
private accessor_name
|
906
|
-
end
|
907
|
-
end
|
908
|
-
include methods
|
909
|
-
end
|
910
|
-
|
911
|
-
def uses_transaction(*methods)
|
912
|
-
@uses_transaction = [] unless defined?(@uses_transaction)
|
913
|
-
@uses_transaction.concat methods.map { |m| m.to_s }
|
914
|
-
end
|
915
|
-
|
916
|
-
def uses_transaction?(method)
|
917
|
-
@uses_transaction = [] unless defined?(@uses_transaction)
|
918
|
-
@uses_transaction.include?(method.to_s)
|
919
|
-
end
|
920
|
-
end
|
921
|
-
|
922
|
-
def run_in_transaction?
|
923
|
-
use_transactional_fixtures &&
|
924
|
-
!self.class.uses_transaction?(method_name)
|
925
|
-
end
|
926
|
-
|
927
|
-
def setup_fixtures(config = ActiveRecord::Base)
|
928
|
-
if pre_loaded_fixtures && !use_transactional_fixtures
|
929
|
-
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
930
|
-
end
|
931
|
-
|
932
|
-
@fixture_cache = {}
|
933
|
-
@fixture_connections = []
|
934
|
-
@@already_loaded_fixtures ||= {}
|
935
|
-
|
936
|
-
# Load fixtures once and begin transaction.
|
937
|
-
if run_in_transaction?
|
938
|
-
if @@already_loaded_fixtures[self.class]
|
939
|
-
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
940
|
-
else
|
941
|
-
@loaded_fixtures = load_fixtures(config)
|
942
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
943
|
-
end
|
944
|
-
@fixture_connections = enlist_fixture_connections
|
945
|
-
@fixture_connections.each do |connection|
|
946
|
-
connection.begin_transaction joinable: false
|
947
|
-
end
|
948
|
-
# Load fixtures for every test.
|
949
|
-
else
|
950
|
-
ActiveRecord::FixtureSet.reset_cache
|
951
|
-
@@already_loaded_fixtures[self.class] = nil
|
952
|
-
@loaded_fixtures = load_fixtures(config)
|
953
|
-
end
|
954
|
-
|
955
|
-
# Instantiate fixtures for every test if requested.
|
956
|
-
instantiate_fixtures if use_instantiated_fixtures
|
957
|
-
end
|
958
|
-
|
959
|
-
def teardown_fixtures
|
960
|
-
# Rollback changes if a transaction is active.
|
961
|
-
if run_in_transaction?
|
962
|
-
@fixture_connections.each do |connection|
|
963
|
-
connection.rollback_transaction if connection.transaction_open?
|
964
|
-
end
|
965
|
-
@fixture_connections.clear
|
966
|
-
else
|
967
|
-
ActiveRecord::FixtureSet.reset_cache
|
968
|
-
end
|
969
|
-
|
970
|
-
ActiveRecord::Base.clear_active_connections!
|
971
|
-
end
|
972
|
-
|
973
|
-
def enlist_fixture_connections
|
974
|
-
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
975
|
-
end
|
976
|
-
|
977
|
-
private
|
978
|
-
def load_fixtures(config)
|
979
|
-
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
980
|
-
Hash[fixtures.map { |f| [f.name, f] }]
|
981
|
-
end
|
982
|
-
|
983
|
-
def instantiate_fixtures
|
984
|
-
if pre_loaded_fixtures
|
985
|
-
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
986
|
-
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
987
|
-
else
|
988
|
-
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
989
|
-
@loaded_fixtures.each_value do |fixture_set|
|
990
|
-
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
991
|
-
end
|
992
|
-
end
|
993
|
-
end
|
994
|
-
|
995
|
-
def load_instances?
|
996
|
-
use_instantiated_fixtures != :no_instances
|
997
|
-
end
|
998
|
-
end
|
999
|
-
end
|
1000
|
-
|
1001
|
-
class ActiveRecord::FixtureSet::RenderContext # :nodoc:
|
1002
|
-
def self.create_subclass
|
1003
|
-
Class.new ActiveRecord::FixtureSet.context_class do
|
1004
|
-
def get_binding
|
1005
|
-
binding()
|
775
|
+
raise FixtureClassNotFound, "No class attached to find." unless model_class
|
776
|
+
object = model_class.unscoped do
|
777
|
+
model_class.find(fixture[model_class.primary_key])
|
1006
778
|
end
|
779
|
+
# Fixtures can't be eagerly loaded
|
780
|
+
object.instance_variable_set(:@strict_loading, false)
|
781
|
+
object
|
1007
782
|
end
|
1008
783
|
end
|
1009
784
|
end
|