activerecord 5.2.5 → 6.0.0.beta1
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 +299 -748
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -42
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/arel.rb +44 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +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.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -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 +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +104 -26
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/fixture_set/table_row"
|
4
|
+
require "active_record/fixture_set/model_metadata"
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
class FixtureSet
|
8
|
+
class TableRows # :nodoc:
|
9
|
+
def initialize(table_name, model_class:, fixtures:, config:)
|
10
|
+
@model_class = model_class
|
11
|
+
|
12
|
+
# track any join tables we need to insert later
|
13
|
+
@tables = Hash.new { |h, table| h[table] = [] }
|
14
|
+
|
15
|
+
# ensure this table is loaded before any HABTM associations
|
16
|
+
@tables[table_name] = nil
|
17
|
+
|
18
|
+
build_table_rows_from(table_name, fixtures, config)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :tables, :model_class
|
22
|
+
|
23
|
+
def to_hash
|
24
|
+
@tables.transform_values { |rows| rows.map(&:to_hash) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def model_metadata
|
28
|
+
@model_metadata ||= ModelMetadata.new(model_class)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def build_table_rows_from(table_name, fixtures, config)
|
34
|
+
now = config.default_timezone == :utc ? Time.now.utc : Time.now
|
35
|
+
|
36
|
+
@tables[table_name] = fixtures.map do |label, fixture|
|
37
|
+
TableRow.new(
|
38
|
+
fixture,
|
39
|
+
table_rows: self,
|
40
|
+
label: label,
|
41
|
+
now: now,
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -7,6 +7,9 @@ require "set"
|
|
7
7
|
require "active_support/dependencies"
|
8
8
|
require "active_support/core_ext/digest/uuid"
|
9
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"
|
10
13
|
require "active_record/errors"
|
11
14
|
|
12
15
|
module ActiveRecord
|
@@ -179,8 +182,8 @@ module ActiveRecord
|
|
179
182
|
# end
|
180
183
|
# end
|
181
184
|
#
|
182
|
-
# If you preload your test database with all fixture data (probably
|
183
|
-
# transactional tests, then you may omit all fixtures declarations in your test cases since
|
185
|
+
# If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
|
186
|
+
# and use transactional tests, then you may omit all fixtures declarations in your test cases since
|
184
187
|
# all the data's already there and every case rolls back its changes.
|
185
188
|
#
|
186
189
|
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
|
@@ -440,60 +443,6 @@ module ActiveRecord
|
|
440
443
|
|
441
444
|
@@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
|
442
445
|
|
443
|
-
def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
444
|
-
config.pluralize_table_names ?
|
445
|
-
fixture_set_name.singularize.camelize :
|
446
|
-
fixture_set_name.camelize
|
447
|
-
end
|
448
|
-
|
449
|
-
def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
450
|
-
"#{ config.table_name_prefix }"\
|
451
|
-
"#{ fixture_set_name.tr('/', '_') }"\
|
452
|
-
"#{ config.table_name_suffix }".to_sym
|
453
|
-
end
|
454
|
-
|
455
|
-
def self.reset_cache
|
456
|
-
@@all_cached_fixtures.clear
|
457
|
-
end
|
458
|
-
|
459
|
-
def self.cache_for_connection(connection)
|
460
|
-
@@all_cached_fixtures[connection]
|
461
|
-
end
|
462
|
-
|
463
|
-
def self.fixture_is_cached?(connection, table_name)
|
464
|
-
cache_for_connection(connection)[table_name]
|
465
|
-
end
|
466
|
-
|
467
|
-
def self.cached_fixtures(connection, keys_to_fetch = nil)
|
468
|
-
if keys_to_fetch
|
469
|
-
cache_for_connection(connection).values_at(*keys_to_fetch)
|
470
|
-
else
|
471
|
-
cache_for_connection(connection).values
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
def self.cache_fixtures(connection, fixtures_map)
|
476
|
-
cache_for_connection(connection).update(fixtures_map)
|
477
|
-
end
|
478
|
-
|
479
|
-
def self.instantiate_fixtures(object, fixture_set, load_instances = true)
|
480
|
-
if load_instances
|
481
|
-
fixture_set.each do |fixture_name, fixture|
|
482
|
-
begin
|
483
|
-
object.instance_variable_set "@#{fixture_name}", fixture.find
|
484
|
-
rescue FixtureClassNotFound
|
485
|
-
nil
|
486
|
-
end
|
487
|
-
end
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
def self.instantiate_all_loaded_fixtures(object, load_instances = true)
|
492
|
-
all_loaded_fixtures.each_value do |fixture_set|
|
493
|
-
instantiate_fixtures(object, fixture_set, load_instances)
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
446
|
cattr_accessor :all_loaded_fixtures, default: {}
|
498
447
|
|
499
448
|
class ClassCache
|
@@ -502,14 +451,16 @@ module ActiveRecord
|
|
502
451
|
@config = config
|
503
452
|
|
504
453
|
# Remove string values that aren't constants or subclasses of AR
|
505
|
-
@class_names.delete_if
|
454
|
+
@class_names.delete_if do |klass_name, klass|
|
455
|
+
!insert_class(@class_names, klass_name, klass)
|
456
|
+
end
|
506
457
|
end
|
507
458
|
|
508
459
|
def [](fs_name)
|
509
|
-
@class_names.fetch(fs_name)
|
460
|
+
@class_names.fetch(fs_name) do
|
510
461
|
klass = default_fixture_model(fs_name, @config).safe_constantize
|
511
462
|
insert_class(@class_names, fs_name, klass)
|
512
|
-
|
463
|
+
end
|
513
464
|
end
|
514
465
|
|
515
466
|
private
|
@@ -528,76 +479,146 @@ module ActiveRecord
|
|
528
479
|
end
|
529
480
|
end
|
530
481
|
|
531
|
-
|
532
|
-
|
533
|
-
|
482
|
+
class << self
|
483
|
+
def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
484
|
+
config.pluralize_table_names ?
|
485
|
+
fixture_set_name.singularize.camelize :
|
486
|
+
fixture_set_name.camelize
|
487
|
+
end
|
534
488
|
|
535
|
-
|
536
|
-
|
489
|
+
def default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
490
|
+
"#{ config.table_name_prefix }"\
|
491
|
+
"#{ fixture_set_name.tr('/', '_') }"\
|
492
|
+
"#{ config.table_name_suffix }".to_sym
|
493
|
+
end
|
537
494
|
|
538
|
-
|
539
|
-
|
540
|
-
|
495
|
+
def reset_cache
|
496
|
+
@@all_cached_fixtures.clear
|
497
|
+
end
|
541
498
|
|
542
|
-
|
543
|
-
|
499
|
+
def cache_for_connection(connection)
|
500
|
+
@@all_cached_fixtures[connection]
|
501
|
+
end
|
544
502
|
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
503
|
+
def fixture_is_cached?(connection, table_name)
|
504
|
+
cache_for_connection(connection)[table_name]
|
505
|
+
end
|
506
|
+
|
507
|
+
def cached_fixtures(connection, keys_to_fetch = nil)
|
508
|
+
if keys_to_fetch
|
509
|
+
cache_for_connection(connection).values_at(*keys_to_fetch)
|
510
|
+
else
|
511
|
+
cache_for_connection(connection).values
|
553
512
|
end
|
513
|
+
end
|
554
514
|
|
555
|
-
|
556
|
-
|
515
|
+
def cache_fixtures(connection, fixtures_map)
|
516
|
+
cache_for_connection(connection).update(fixtures_map)
|
517
|
+
end
|
557
518
|
|
558
|
-
|
559
|
-
|
519
|
+
def instantiate_fixtures(object, fixture_set, load_instances = true)
|
520
|
+
return unless load_instances
|
521
|
+
fixture_set.each do |fixture_name, fixture|
|
522
|
+
object.instance_variable_set "@#{fixture_name}", fixture.find
|
523
|
+
rescue FixtureClassNotFound
|
524
|
+
nil
|
525
|
+
end
|
526
|
+
end
|
560
527
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
528
|
+
def instantiate_all_loaded_fixtures(object, load_instances = true)
|
529
|
+
all_loaded_fixtures.each_value do |fixture_set|
|
530
|
+
instantiate_fixtures(object, fixture_set, load_instances)
|
531
|
+
end
|
532
|
+
end
|
567
533
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
534
|
+
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
535
|
+
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
536
|
+
class_names = ClassCache.new class_names, config
|
537
|
+
|
538
|
+
# FIXME: Apparently JK uses this.
|
539
|
+
connection = block_given? ? yield : ActiveRecord::Base.connection
|
540
|
+
|
541
|
+
fixture_files_to_read = fixture_set_names.reject do |fs_name|
|
542
|
+
fixture_is_cached?(connection, fs_name)
|
572
543
|
end
|
573
544
|
|
574
|
-
|
545
|
+
if fixture_files_to_read.any?
|
546
|
+
fixtures_map = read_and_insert(
|
547
|
+
fixtures_directory,
|
548
|
+
fixture_files_to_read,
|
549
|
+
class_names,
|
550
|
+
connection,
|
551
|
+
)
|
552
|
+
cache_fixtures(connection, fixtures_map)
|
553
|
+
end
|
554
|
+
cached_fixtures(connection, fixture_set_names)
|
575
555
|
end
|
576
|
-
cached_fixtures(connection, fixture_set_names)
|
577
|
-
end
|
578
556
|
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
557
|
+
# Returns a consistent, platform-independent identifier for +label+.
|
558
|
+
# Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
|
559
|
+
def identify(label, column_type = :integer)
|
560
|
+
if column_type == :uuid
|
561
|
+
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
|
562
|
+
else
|
563
|
+
Zlib.crc32(label.to_s) % MAX_ID
|
564
|
+
end
|
586
565
|
end
|
587
|
-
end
|
588
566
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
567
|
+
# Superclass for the evaluation contexts used by ERB fixtures.
|
568
|
+
def context_class
|
569
|
+
@context_class ||= Class.new
|
570
|
+
end
|
593
571
|
|
594
|
-
|
595
|
-
|
572
|
+
private
|
573
|
+
|
574
|
+
def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
|
575
|
+
fixtures_map = {}
|
576
|
+
fixture_sets = fixture_files.map do |fixture_set_name|
|
577
|
+
klass = class_names[fixture_set_name]
|
578
|
+
fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
|
579
|
+
nil,
|
580
|
+
fixture_set_name,
|
581
|
+
klass,
|
582
|
+
::File.join(fixtures_directory, fixture_set_name)
|
583
|
+
)
|
584
|
+
end
|
585
|
+
update_all_loaded_fixtures(fixtures_map)
|
586
|
+
|
587
|
+
insert(fixture_sets, connection)
|
588
|
+
|
589
|
+
fixtures_map
|
590
|
+
end
|
591
|
+
|
592
|
+
def insert(fixture_sets, connection) # :nodoc:
|
593
|
+
fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
|
594
|
+
fixture_set.model_class&.connection || connection
|
595
|
+
end
|
596
|
+
|
597
|
+
fixture_sets_by_connection.each do |conn, set|
|
598
|
+
table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
|
599
|
+
|
600
|
+
set.each do |fixture_set|
|
601
|
+
fixture_set.table_rows.each do |table, rows|
|
602
|
+
table_rows_for_connection[table].unshift(*rows)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
|
606
|
+
|
607
|
+
# Cap primary key sequences to max(pk).
|
608
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
609
|
+
set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def update_all_loaded_fixtures(fixtures_map) # :nodoc:
|
615
|
+
all_loaded_fixtures.update(fixtures_map)
|
616
|
+
end
|
596
617
|
end
|
597
618
|
|
598
619
|
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
599
620
|
|
600
|
-
def initialize(
|
621
|
+
def initialize(_, name, class_name, path, config = ActiveRecord::Base)
|
601
622
|
@name = name
|
602
623
|
@path = path
|
603
624
|
@config = config
|
@@ -606,11 +627,7 @@ module ActiveRecord
|
|
606
627
|
|
607
628
|
@fixtures = read_fixture_files(path)
|
608
629
|
|
609
|
-
@
|
610
|
-
|
611
|
-
@table_name = (model_class.respond_to?(:table_name) ?
|
612
|
-
model_class.table_name :
|
613
|
-
self.class.default_fixture_table_name(name, config))
|
630
|
+
@table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
|
614
631
|
end
|
615
632
|
|
616
633
|
def [](x)
|
@@ -632,152 +649,18 @@ module ActiveRecord
|
|
632
649
|
# Returns a hash of rows to be inserted. The key is the table, the value is
|
633
650
|
# a list of rows to insert to that table.
|
634
651
|
def table_rows
|
635
|
-
now = config.default_timezone == :utc ? Time.now.utc : Time.now
|
636
|
-
|
637
652
|
# allow a standard key to be used for doing defaults in YAML
|
638
653
|
fixtures.delete("DEFAULTS")
|
639
654
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
if model_class
|
647
|
-
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
|
648
|
-
if model_class.record_timestamps
|
649
|
-
timestamp_column_names.each do |c_name|
|
650
|
-
row[c_name] = now unless row.key?(c_name)
|
651
|
-
end
|
652
|
-
end
|
653
|
-
|
654
|
-
# interpolate the fixture label
|
655
|
-
row.each do |key, value|
|
656
|
-
row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
|
657
|
-
end
|
658
|
-
|
659
|
-
# generate a primary key if necessary
|
660
|
-
if has_primary_key_column? && !row.include?(primary_key_name)
|
661
|
-
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
|
662
|
-
end
|
663
|
-
|
664
|
-
# Resolve enums
|
665
|
-
model_class.defined_enums.each do |name, values|
|
666
|
-
if row.include?(name)
|
667
|
-
row[name] = values.fetch(row[name], row[name])
|
668
|
-
end
|
669
|
-
end
|
670
|
-
|
671
|
-
# If STI is used, find the correct subclass for association reflection
|
672
|
-
reflection_class =
|
673
|
-
if row.include?(inheritance_column_name)
|
674
|
-
row[inheritance_column_name].constantize rescue model_class
|
675
|
-
else
|
676
|
-
model_class
|
677
|
-
end
|
678
|
-
|
679
|
-
reflection_class._reflections.each_value do |association|
|
680
|
-
case association.macro
|
681
|
-
when :belongs_to
|
682
|
-
# Do not replace association name with association foreign key if they are named the same
|
683
|
-
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
684
|
-
|
685
|
-
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
686
|
-
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
687
|
-
# support polymorphic belongs_to as "label (Type)"
|
688
|
-
row[association.foreign_type] = $1
|
689
|
-
end
|
690
|
-
|
691
|
-
fk_type = reflection_class.type_for_attribute(fk_name).type
|
692
|
-
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
693
|
-
end
|
694
|
-
when :has_many
|
695
|
-
if association.options[:through]
|
696
|
-
add_join_records(rows, row, HasManyThroughProxy.new(association))
|
697
|
-
end
|
698
|
-
end
|
699
|
-
end
|
700
|
-
end
|
701
|
-
|
702
|
-
row
|
703
|
-
end
|
704
|
-
rows
|
705
|
-
end
|
706
|
-
|
707
|
-
class ReflectionProxy # :nodoc:
|
708
|
-
def initialize(association)
|
709
|
-
@association = association
|
710
|
-
end
|
711
|
-
|
712
|
-
def join_table
|
713
|
-
@association.join_table
|
714
|
-
end
|
715
|
-
|
716
|
-
def name
|
717
|
-
@association.name
|
718
|
-
end
|
719
|
-
|
720
|
-
def primary_key_type
|
721
|
-
@association.klass.type_for_attribute(@association.klass.primary_key).type
|
722
|
-
end
|
723
|
-
end
|
724
|
-
|
725
|
-
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
726
|
-
def rhs_key
|
727
|
-
@association.foreign_key
|
728
|
-
end
|
729
|
-
|
730
|
-
def lhs_key
|
731
|
-
@association.through_reflection.foreign_key
|
732
|
-
end
|
733
|
-
|
734
|
-
def join_table
|
735
|
-
@association.through_reflection.table_name
|
736
|
-
end
|
655
|
+
TableRows.new(
|
656
|
+
table_name,
|
657
|
+
model_class: model_class,
|
658
|
+
fixtures: fixtures,
|
659
|
+
config: config,
|
660
|
+
).to_hash
|
737
661
|
end
|
738
662
|
|
739
663
|
private
|
740
|
-
def primary_key_name
|
741
|
-
@primary_key_name ||= model_class && model_class.primary_key
|
742
|
-
end
|
743
|
-
|
744
|
-
def primary_key_type
|
745
|
-
@primary_key_type ||= model_class && model_class.type_for_attribute(model_class.primary_key).type
|
746
|
-
end
|
747
|
-
|
748
|
-
def add_join_records(rows, row, association)
|
749
|
-
# This is the case when the join table has no fixtures file
|
750
|
-
if (targets = row.delete(association.name.to_s))
|
751
|
-
table_name = association.join_table
|
752
|
-
column_type = association.primary_key_type
|
753
|
-
lhs_key = association.lhs_key
|
754
|
-
rhs_key = association.rhs_key
|
755
|
-
|
756
|
-
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
757
|
-
rows[table_name].concat targets.map { |target|
|
758
|
-
{ lhs_key => row[primary_key_name],
|
759
|
-
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
760
|
-
}
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
|
-
def has_primary_key_column?
|
765
|
-
@has_primary_key_column ||= primary_key_name &&
|
766
|
-
model_class.columns.any? { |c| c.name == primary_key_name }
|
767
|
-
end
|
768
|
-
|
769
|
-
def timestamp_column_names
|
770
|
-
@timestamp_column_names ||=
|
771
|
-
%w(created_at created_on updated_at updated_on) & column_names
|
772
|
-
end
|
773
|
-
|
774
|
-
def inheritance_column_name
|
775
|
-
@inheritance_column_name ||= model_class && model_class.inheritance_column
|
776
|
-
end
|
777
|
-
|
778
|
-
def column_names
|
779
|
-
@column_names ||= @connection.columns(@table_name).collect(&:name)
|
780
|
-
end
|
781
664
|
|
782
665
|
def model_class=(class_name)
|
783
666
|
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
@@ -841,224 +724,9 @@ module ActiveRecord
|
|
841
724
|
alias :to_hash :fixture
|
842
725
|
|
843
726
|
def find
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
end
|
848
|
-
else
|
849
|
-
raise FixtureClassNotFound, "No class attached to find."
|
850
|
-
end
|
851
|
-
end
|
852
|
-
end
|
853
|
-
end
|
854
|
-
|
855
|
-
module ActiveRecord
|
856
|
-
module TestFixtures
|
857
|
-
extend ActiveSupport::Concern
|
858
|
-
|
859
|
-
def before_setup # :nodoc:
|
860
|
-
setup_fixtures
|
861
|
-
super
|
862
|
-
end
|
863
|
-
|
864
|
-
def after_teardown # :nodoc:
|
865
|
-
super
|
866
|
-
teardown_fixtures
|
867
|
-
end
|
868
|
-
|
869
|
-
included do
|
870
|
-
class_attribute :fixture_path, instance_writer: false
|
871
|
-
class_attribute :fixture_table_names, default: []
|
872
|
-
class_attribute :fixture_class_names, default: {}
|
873
|
-
class_attribute :use_transactional_tests, default: true
|
874
|
-
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
875
|
-
class_attribute :pre_loaded_fixtures, default: false
|
876
|
-
class_attribute :config, default: ActiveRecord::Base
|
877
|
-
end
|
878
|
-
|
879
|
-
module ClassMethods
|
880
|
-
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
881
|
-
#
|
882
|
-
# Examples:
|
883
|
-
#
|
884
|
-
# set_fixture_class some_fixture: SomeModel,
|
885
|
-
# 'namespaced/fixture' => Another::Model
|
886
|
-
#
|
887
|
-
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
888
|
-
def set_fixture_class(class_names = {})
|
889
|
-
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
890
|
-
end
|
891
|
-
|
892
|
-
def fixtures(*fixture_set_names)
|
893
|
-
if fixture_set_names.first == :all
|
894
|
-
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
|
895
|
-
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
896
|
-
else
|
897
|
-
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
898
|
-
end
|
899
|
-
|
900
|
-
self.fixture_table_names |= fixture_set_names
|
901
|
-
setup_fixture_accessors(fixture_set_names)
|
902
|
-
end
|
903
|
-
|
904
|
-
def setup_fixture_accessors(fixture_set_names = nil)
|
905
|
-
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
906
|
-
methods = Module.new do
|
907
|
-
fixture_set_names.each do |fs_name|
|
908
|
-
fs_name = fs_name.to_s
|
909
|
-
accessor_name = fs_name.tr("/", "_").to_sym
|
910
|
-
|
911
|
-
define_method(accessor_name) do |*fixture_names|
|
912
|
-
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
913
|
-
return_single_record = fixture_names.size == 1
|
914
|
-
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
915
|
-
|
916
|
-
@fixture_cache[fs_name] ||= {}
|
917
|
-
|
918
|
-
instances = fixture_names.map do |f_name|
|
919
|
-
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
920
|
-
@fixture_cache[fs_name].delete(f_name) if force_reload
|
921
|
-
|
922
|
-
if @loaded_fixtures[fs_name][f_name]
|
923
|
-
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
924
|
-
else
|
925
|
-
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
926
|
-
end
|
927
|
-
end
|
928
|
-
|
929
|
-
return_single_record ? instances.first : instances
|
930
|
-
end
|
931
|
-
private accessor_name
|
932
|
-
end
|
933
|
-
end
|
934
|
-
include methods
|
935
|
-
end
|
936
|
-
|
937
|
-
def uses_transaction(*methods)
|
938
|
-
@uses_transaction = [] unless defined?(@uses_transaction)
|
939
|
-
@uses_transaction.concat methods.map(&:to_s)
|
940
|
-
end
|
941
|
-
|
942
|
-
def uses_transaction?(method)
|
943
|
-
@uses_transaction = [] unless defined?(@uses_transaction)
|
944
|
-
@uses_transaction.include?(method.to_s)
|
945
|
-
end
|
946
|
-
end
|
947
|
-
|
948
|
-
def run_in_transaction?
|
949
|
-
use_transactional_tests &&
|
950
|
-
!self.class.uses_transaction?(method_name)
|
951
|
-
end
|
952
|
-
|
953
|
-
def setup_fixtures(config = ActiveRecord::Base)
|
954
|
-
if pre_loaded_fixtures && !use_transactional_tests
|
955
|
-
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
956
|
-
end
|
957
|
-
|
958
|
-
@fixture_cache = {}
|
959
|
-
@fixture_connections = []
|
960
|
-
@@already_loaded_fixtures ||= {}
|
961
|
-
@connection_subscriber = nil
|
962
|
-
|
963
|
-
# Load fixtures once and begin transaction.
|
964
|
-
if run_in_transaction?
|
965
|
-
if @@already_loaded_fixtures[self.class]
|
966
|
-
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
967
|
-
else
|
968
|
-
@loaded_fixtures = load_fixtures(config)
|
969
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
970
|
-
end
|
971
|
-
|
972
|
-
# Begin transactions for connections already established
|
973
|
-
@fixture_connections = enlist_fixture_connections
|
974
|
-
@fixture_connections.each do |connection|
|
975
|
-
connection.begin_transaction joinable: false
|
976
|
-
connection.pool.lock_thread = true
|
977
|
-
end
|
978
|
-
|
979
|
-
# When connections are established in the future, begin a transaction too
|
980
|
-
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
981
|
-
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
982
|
-
|
983
|
-
if spec_name
|
984
|
-
begin
|
985
|
-
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
986
|
-
rescue ConnectionNotEstablished
|
987
|
-
connection = nil
|
988
|
-
end
|
989
|
-
|
990
|
-
if connection && !@fixture_connections.include?(connection)
|
991
|
-
connection.begin_transaction joinable: false
|
992
|
-
connection.pool.lock_thread = true
|
993
|
-
@fixture_connections << connection
|
994
|
-
end
|
995
|
-
end
|
996
|
-
end
|
997
|
-
|
998
|
-
# Load fixtures for every test.
|
999
|
-
else
|
1000
|
-
ActiveRecord::FixtureSet.reset_cache
|
1001
|
-
@@already_loaded_fixtures[self.class] = nil
|
1002
|
-
@loaded_fixtures = load_fixtures(config)
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
# Instantiate fixtures for every test if requested.
|
1006
|
-
instantiate_fixtures if use_instantiated_fixtures
|
1007
|
-
end
|
1008
|
-
|
1009
|
-
def teardown_fixtures
|
1010
|
-
# Rollback changes if a transaction is active.
|
1011
|
-
if run_in_transaction?
|
1012
|
-
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
1013
|
-
@fixture_connections.each do |connection|
|
1014
|
-
connection.rollback_transaction if connection.transaction_open?
|
1015
|
-
connection.pool.lock_thread = false
|
1016
|
-
end
|
1017
|
-
@fixture_connections.clear
|
1018
|
-
else
|
1019
|
-
ActiveRecord::FixtureSet.reset_cache
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
ActiveRecord::Base.clear_active_connections!
|
1023
|
-
end
|
1024
|
-
|
1025
|
-
def enlist_fixture_connections
|
1026
|
-
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
1027
|
-
end
|
1028
|
-
|
1029
|
-
private
|
1030
|
-
def load_fixtures(config)
|
1031
|
-
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
1032
|
-
Hash[fixtures.map { |f| [f.name, f] }]
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
def instantiate_fixtures
|
1036
|
-
if pre_loaded_fixtures
|
1037
|
-
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
1038
|
-
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
1039
|
-
else
|
1040
|
-
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
1041
|
-
@loaded_fixtures.each_value do |fixture_set|
|
1042
|
-
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
1043
|
-
end
|
1044
|
-
end
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
def load_instances?
|
1048
|
-
use_instantiated_fixtures != :no_instances
|
1049
|
-
end
|
1050
|
-
end
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
class ActiveRecord::FixtureSet::RenderContext # :nodoc:
|
1054
|
-
def self.create_subclass
|
1055
|
-
Class.new ActiveRecord::FixtureSet.context_class do
|
1056
|
-
def get_binding
|
1057
|
-
binding()
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
def binary(path)
|
1061
|
-
%(!!binary "#{Base64.strict_encode64(File.read(path))}")
|
727
|
+
raise FixtureClassNotFound, "No class attached to find." unless model_class
|
728
|
+
model_class.unscoped do
|
729
|
+
model_class.find(fixture[model_class.primary_key])
|
1062
730
|
end
|
1063
731
|
end
|
1064
732
|
end
|