activerecord 3.2.19 → 5.0.0
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 +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,36 +1,25 @@
|
|
1
1
|
require 'erb'
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'psych'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
2
|
require 'yaml'
|
9
3
|
require 'zlib'
|
4
|
+
require 'set'
|
10
5
|
require 'active_support/dependencies'
|
11
|
-
require 'active_support/core_ext/
|
12
|
-
require '
|
13
|
-
require '
|
14
|
-
require 'active_support/ordered_hash'
|
15
|
-
require 'active_record/fixtures/file'
|
6
|
+
require 'active_support/core_ext/digest/uuid'
|
7
|
+
require 'active_record/fixture_set/file'
|
8
|
+
require 'active_record/errors'
|
16
9
|
|
17
|
-
|
10
|
+
module ActiveRecord
|
18
11
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
19
12
|
end
|
20
|
-
else
|
21
|
-
class FixtureClassNotFound < StandardError #:nodoc:
|
22
|
-
end
|
23
|
-
end
|
24
13
|
|
25
|
-
module ActiveRecord
|
26
14
|
# \Fixtures are a way of organizing data that you want to test against; in short, sample data.
|
27
15
|
#
|
28
16
|
# They are stored in YAML files, one file per model, which are placed in the directory
|
29
17
|
# appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
|
30
18
|
# configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
|
31
|
-
# The fixture file ends with the
|
32
|
-
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
33
|
-
#
|
19
|
+
# The fixture file ends with the +.yml+ file extension, for example:
|
20
|
+
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
21
|
+
#
|
22
|
+
# The format of a fixture file looks like this:
|
34
23
|
#
|
35
24
|
# rubyonrails:
|
36
25
|
# id: 1
|
@@ -46,7 +35,7 @@ module ActiveRecord
|
|
46
35
|
# is followed by an indented list of key/value pairs in the "key: value" format. Records are
|
47
36
|
# separated by a blank line for your viewing pleasure.
|
48
37
|
#
|
49
|
-
# Note
|
38
|
+
# Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
|
50
39
|
# See http://yaml.org/type/omap.html
|
51
40
|
# for the specification. You will need ordered fixtures when you have foreign key constraints
|
52
41
|
# on keys in the same table. This is commonly needed for tree structures. Example:
|
@@ -74,8 +63,8 @@ module ActiveRecord
|
|
74
63
|
# end
|
75
64
|
# end
|
76
65
|
#
|
77
|
-
# By default,
|
78
|
-
# so this test will succeed.
|
66
|
+
# By default, +test_helper.rb+ will load all of your fixtures into your test
|
67
|
+
# database, so this test will succeed.
|
79
68
|
#
|
80
69
|
# The testing environment will automatically load the all fixtures into the database before each
|
81
70
|
# test. To ensure consistent data, the environment deletes the fixtures before running the load.
|
@@ -96,11 +85,11 @@ module ActiveRecord
|
|
96
85
|
# end
|
97
86
|
#
|
98
87
|
# test "find_alt_method_2" do
|
99
|
-
# assert_equal "Ruby on Rails", @rubyonrails.
|
88
|
+
# assert_equal "Ruby on Rails", @rubyonrails.name
|
100
89
|
# end
|
101
90
|
#
|
102
91
|
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
|
103
|
-
# following in your
|
92
|
+
# following in your ActiveSupport::TestCase-derived class:
|
104
93
|
#
|
105
94
|
# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
|
106
95
|
# self.use_instantiated_fixtures = true
|
@@ -121,7 +110,7 @@ module ActiveRecord
|
|
121
110
|
# <% 1.upto(1000) do |i| %>
|
122
111
|
# fix_<%= i %>:
|
123
112
|
# id: <%= i %>
|
124
|
-
# name: guy_<%=
|
113
|
+
# name: guy_<%= i %>
|
125
114
|
# <% end %>
|
126
115
|
#
|
127
116
|
# This will create 1000 very simple fixtures.
|
@@ -133,13 +122,30 @@ module ActiveRecord
|
|
133
122
|
# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
|
134
123
|
# in fixtures are to be considered a code smell.
|
135
124
|
#
|
136
|
-
#
|
125
|
+
# Helper methods defined in a fixture will not be available in other fixtures, to prevent against
|
126
|
+
# unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
|
127
|
+
# that is included in ActiveRecord::FixtureSet.context_class.
|
128
|
+
#
|
129
|
+
# - define a helper method in `test_helper.rb`
|
130
|
+
# module FixtureFileHelpers
|
131
|
+
# def file_sha(path)
|
132
|
+
# Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
# ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
|
136
|
+
#
|
137
|
+
# - use the helper method in a fixture
|
138
|
+
# photo:
|
139
|
+
# name: kitten.png
|
140
|
+
# sha: <%= file_sha 'files/kitten.png' %>
|
141
|
+
#
|
142
|
+
# = Transactional Tests
|
137
143
|
#
|
138
144
|
# Test cases can use begin+rollback to isolate their changes to the database instead of having to
|
139
145
|
# delete+insert for every test case.
|
140
146
|
#
|
141
147
|
# class FooTest < ActiveSupport::TestCase
|
142
|
-
# self.
|
148
|
+
# self.use_transactional_tests = true
|
143
149
|
#
|
144
150
|
# test "godzilla" do
|
145
151
|
# assert !Foo.all.empty?
|
@@ -153,14 +159,14 @@ module ActiveRecord
|
|
153
159
|
# end
|
154
160
|
#
|
155
161
|
# If you preload your test database with all fixture data (probably in the rake task) and use
|
156
|
-
# transactional
|
162
|
+
# transactional tests, then you may omit all fixtures declarations in your test cases since
|
157
163
|
# all the data's already there and every case rolls back its changes.
|
158
164
|
#
|
159
165
|
# In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
|
160
166
|
# true. This will provide access to fixture data for every table that has been loaded through
|
161
167
|
# fixtures (depending on the value of +use_instantiated_fixtures+).
|
162
168
|
#
|
163
|
-
# When *not* to use transactional
|
169
|
+
# When *not* to use transactional tests:
|
164
170
|
#
|
165
171
|
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
|
166
172
|
# all parent transactions commit, particularly, the fixtures transaction which is begun in setup
|
@@ -176,6 +182,9 @@ module ActiveRecord
|
|
176
182
|
# * Stable, autogenerated IDs
|
177
183
|
# * Label references for associations (belongs_to, has_one, has_many)
|
178
184
|
# * HABTM associations as inline lists
|
185
|
+
#
|
186
|
+
# There are some more advanced features available even if the id is specified:
|
187
|
+
#
|
179
188
|
# * Autofilled timestamp columns
|
180
189
|
# * Fixture label interpolation
|
181
190
|
# * Support for YAML defaults
|
@@ -262,7 +271,7 @@ module ActiveRecord
|
|
262
271
|
#
|
263
272
|
# ### in fruit.rb
|
264
273
|
#
|
265
|
-
# belongs_to :eater, :
|
274
|
+
# belongs_to :eater, polymorphic: true
|
266
275
|
#
|
267
276
|
# ### in fruits.yml
|
268
277
|
#
|
@@ -358,41 +367,68 @@ module ActiveRecord
|
|
358
367
|
# geeksomnia:
|
359
368
|
# name: Geeksomnia's Account
|
360
369
|
# subdomain: $LABEL
|
370
|
+
# email: $LABEL@email.com
|
361
371
|
#
|
362
372
|
# Also, sometimes (like when porting older join table fixtures) you'll need
|
363
373
|
# to be able to get a hold of the identifier for a given label. ERB
|
364
374
|
# to the rescue:
|
365
375
|
#
|
366
376
|
# george_reginald:
|
367
|
-
# monkey_id: <%= ActiveRecord::
|
368
|
-
# pirate_id: <%= ActiveRecord::
|
377
|
+
# monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
|
378
|
+
# pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
|
369
379
|
#
|
370
380
|
# == Support for YAML defaults
|
371
381
|
#
|
372
|
-
# You
|
373
|
-
#
|
382
|
+
# You can set and reuse defaults in your fixtures YAML file.
|
383
|
+
# This is the same technique used in the +database.yml+ file to specify
|
384
|
+
# defaults:
|
374
385
|
#
|
375
386
|
# DEFAULTS: &DEFAULTS
|
376
387
|
# created_on: <%= 3.weeks.ago.to_s(:db) %>
|
377
388
|
#
|
378
389
|
# first:
|
379
390
|
# name: Smurf
|
380
|
-
# *DEFAULTS
|
391
|
+
# <<: *DEFAULTS
|
381
392
|
#
|
382
393
|
# second:
|
383
394
|
# name: Fraggle
|
384
|
-
# *DEFAULTS
|
395
|
+
# <<: *DEFAULTS
|
385
396
|
#
|
386
397
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
387
|
-
|
398
|
+
#
|
399
|
+
# == Configure the fixture model class
|
400
|
+
#
|
401
|
+
# It's possible to set the fixture's model class directly in the YAML file.
|
402
|
+
# This is helpful when fixtures are loaded outside tests and
|
403
|
+
# +set_fixture_class+ is not available (e.g.
|
404
|
+
# when running <tt>rails db:fixtures:load</tt>).
|
405
|
+
#
|
406
|
+
# _fixture:
|
407
|
+
# model_class: User
|
408
|
+
# david:
|
409
|
+
# name: David
|
410
|
+
#
|
411
|
+
# Any fixtures labeled "_fixture" are safely ignored.
|
412
|
+
class FixtureSet
|
413
|
+
#--
|
414
|
+
# An instance of FixtureSet is normally stored in a single YAML file and
|
415
|
+
# possibly in a folder with the same name.
|
416
|
+
#++
|
417
|
+
|
388
418
|
MAX_ID = 2 ** 30 - 1
|
389
419
|
|
390
420
|
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
|
391
421
|
|
392
|
-
def self.
|
393
|
-
|
394
|
-
|
395
|
-
|
422
|
+
def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
423
|
+
config.pluralize_table_names ?
|
424
|
+
fixture_set_name.singularize.camelize :
|
425
|
+
fixture_set_name.camelize
|
426
|
+
end
|
427
|
+
|
428
|
+
def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
|
429
|
+
"#{ config.table_name_prefix }"\
|
430
|
+
"#{ fixture_set_name.tr('/', '_') }"\
|
431
|
+
"#{ config.table_name_suffix }".to_sym
|
396
432
|
end
|
397
433
|
|
398
434
|
def self.reset_cache
|
@@ -419,11 +455,7 @@ module ActiveRecord
|
|
419
455
|
cache_for_connection(connection).update(fixtures_map)
|
420
456
|
end
|
421
457
|
|
422
|
-
|
423
|
-
# TODO:NOTE: in the next version, the __with_new_arity suffix and
|
424
|
-
# the method with the old arity will be removed.
|
425
|
-
#++
|
426
|
-
def self.instantiate_fixtures__with_new_arity(object, fixture_set, load_instances = true) # :nodoc:
|
458
|
+
def self.instantiate_fixtures(object, fixture_set, load_instances = true)
|
427
459
|
if load_instances
|
428
460
|
fixture_set.each do |fixture_name, fixture|
|
429
461
|
begin
|
@@ -435,79 +467,96 @@ module ActiveRecord
|
|
435
467
|
end
|
436
468
|
end
|
437
469
|
|
438
|
-
# The use with parameters <tt>(object, fixture_set_name, fixture_set, load_instances = true)</tt> is deprecated, +fixture_set_name+ parameter is not used.
|
439
|
-
# Use as:
|
440
|
-
#
|
441
|
-
# instantiate_fixtures(object, fixture_set, load_instances = true)
|
442
|
-
def self.instantiate_fixtures(object, fixture_set, load_instances = true, rails_3_2_compatibility_argument = true)
|
443
|
-
unless load_instances == true || load_instances == false
|
444
|
-
ActiveSupport::Deprecation.warn(
|
445
|
-
"ActiveRecord::Fixtures.instantiate_fixtures with parameters (object, fixture_set_name, fixture_set, load_instances = true) is deprecated and shall be removed from future releases. Use it with parameters (object, fixture_set, load_instances = true) instead (skip fixture_set_name).",
|
446
|
-
caller)
|
447
|
-
fixture_set = load_instances
|
448
|
-
load_instances = rails_3_2_compatibility_argument
|
449
|
-
end
|
450
|
-
instantiate_fixtures__with_new_arity(object, fixture_set, load_instances)
|
451
|
-
end
|
452
|
-
|
453
470
|
def self.instantiate_all_loaded_fixtures(object, load_instances = true)
|
454
471
|
all_loaded_fixtures.each_value do |fixture_set|
|
455
|
-
|
472
|
+
instantiate_fixtures(object, fixture_set, load_instances)
|
456
473
|
end
|
457
474
|
end
|
458
475
|
|
459
476
|
cattr_accessor :all_loaded_fixtures
|
460
477
|
self.all_loaded_fixtures = {}
|
461
478
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
479
|
+
class ClassCache
|
480
|
+
def initialize(class_names, config)
|
481
|
+
@class_names = class_names.stringify_keys
|
482
|
+
@config = config
|
483
|
+
|
484
|
+
# Remove string values that aren't constants or subclasses of AR
|
485
|
+
@class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
|
486
|
+
end
|
487
|
+
|
488
|
+
def [](fs_name)
|
489
|
+
@class_names.fetch(fs_name) {
|
490
|
+
klass = default_fixture_model(fs_name, @config).safe_constantize
|
491
|
+
insert_class(@class_names, fs_name, klass)
|
492
|
+
}
|
493
|
+
end
|
494
|
+
|
495
|
+
private
|
496
|
+
|
497
|
+
def insert_class(class_names, name, klass)
|
498
|
+
# We only want to deal with AR objects.
|
499
|
+
if klass && klass < ActiveRecord::Base
|
500
|
+
class_names[name] = klass
|
501
|
+
else
|
502
|
+
class_names[name] = nil
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
def default_fixture_model(fs_name, config)
|
507
|
+
ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
|
512
|
+
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
513
|
+
class_names = ClassCache.new class_names, config
|
467
514
|
|
468
515
|
# FIXME: Apparently JK uses this.
|
469
516
|
connection = block_given? ? yield : ActiveRecord::Base.connection
|
470
517
|
|
471
|
-
files_to_read =
|
472
|
-
fixture_is_cached?(connection,
|
518
|
+
files_to_read = fixture_set_names.reject { |fs_name|
|
519
|
+
fixture_is_cached?(connection, fs_name)
|
473
520
|
}
|
474
521
|
|
475
522
|
unless files_to_read.empty?
|
476
523
|
connection.disable_referential_integrity do
|
477
524
|
fixtures_map = {}
|
478
525
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
fixtures_map[
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
::File.join(fixtures_directory,
|
526
|
+
fixture_sets = files_to_read.map do |fs_name|
|
527
|
+
klass = class_names[fs_name]
|
528
|
+
conn = klass ? klass.connection : connection
|
529
|
+
fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
|
530
|
+
conn,
|
531
|
+
fs_name,
|
532
|
+
klass,
|
533
|
+
::File.join(fixtures_directory, fs_name))
|
487
534
|
end
|
488
535
|
|
489
|
-
|
536
|
+
update_all_loaded_fixtures fixtures_map
|
490
537
|
|
491
538
|
connection.transaction(:requires_new => true) do
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
539
|
+
deleted_tables = Set.new
|
540
|
+
fixture_sets.each do |fs|
|
541
|
+
conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
|
542
|
+
table_rows = fs.table_rows
|
543
|
+
|
544
|
+
table_rows.each_key do |table|
|
545
|
+
unless deleted_tables.include? table
|
546
|
+
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
|
547
|
+
end
|
548
|
+
deleted_tables << table
|
498
549
|
end
|
499
550
|
|
500
|
-
table_rows.each do |
|
551
|
+
table_rows.each do |fixture_set_name, rows|
|
501
552
|
rows.each do |row|
|
502
|
-
conn.insert_fixture(row,
|
553
|
+
conn.insert_fixture(row, fixture_set_name)
|
503
554
|
end
|
504
555
|
end
|
505
|
-
end
|
506
556
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
connection.reset_pk_sequence!(table_name.tr('/', '_'))
|
557
|
+
# Cap primary key sequences to max(pk).
|
558
|
+
if conn.respond_to?(:reset_pk_sequence!)
|
559
|
+
conn.reset_pk_sequence!(fs.table_name)
|
511
560
|
end
|
512
561
|
end
|
513
562
|
end
|
@@ -515,37 +564,44 @@ module ActiveRecord
|
|
515
564
|
cache_fixtures(connection, fixtures_map)
|
516
565
|
end
|
517
566
|
end
|
518
|
-
cached_fixtures(connection,
|
567
|
+
cached_fixtures(connection, fixture_set_names)
|
519
568
|
end
|
520
569
|
|
521
570
|
# Returns a consistent, platform-independent identifier for +label+.
|
522
|
-
#
|
523
|
-
def self.identify(label)
|
524
|
-
|
571
|
+
# Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
|
572
|
+
def self.identify(label, column_type = :integer)
|
573
|
+
if column_type == :uuid
|
574
|
+
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
|
575
|
+
else
|
576
|
+
Zlib.crc32(label.to_s) % MAX_ID
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
# Superclass for the evaluation contexts used by ERB fixtures.
|
581
|
+
def self.context_class
|
582
|
+
@context_class ||= Class.new
|
525
583
|
end
|
526
584
|
|
527
|
-
|
585
|
+
def self.update_all_loaded_fixtures(fixtures_map) # :nodoc:
|
586
|
+
all_loaded_fixtures.update(fixtures_map)
|
587
|
+
end
|
528
588
|
|
529
|
-
|
530
|
-
@connection = connection
|
531
|
-
@table_name = table_name
|
532
|
-
@fixture_path = fixture_path
|
533
|
-
@name = table_name # preserve fixture base name
|
534
|
-
@class_name = class_name
|
589
|
+
attr_reader :table_name, :name, :fixtures, :model_class, :config
|
535
590
|
|
536
|
-
|
537
|
-
@
|
591
|
+
def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
|
592
|
+
@name = name
|
593
|
+
@path = path
|
594
|
+
@config = config
|
538
595
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
@connection = class_name.connection
|
543
|
-
@model_class = class_name
|
544
|
-
else
|
545
|
-
@model_class = class_name.constantize rescue nil
|
546
|
-
end
|
596
|
+
self.model_class = class_name
|
597
|
+
|
598
|
+
@fixtures = read_fixture_files(path)
|
547
599
|
|
548
|
-
|
600
|
+
@connection = connection
|
601
|
+
|
602
|
+
@table_name = ( model_class.respond_to?(:table_name) ?
|
603
|
+
model_class.table_name :
|
604
|
+
self.class.default_fixture_table_name(name, config) )
|
549
605
|
end
|
550
606
|
|
551
607
|
def [](x)
|
@@ -564,11 +620,10 @@ module ActiveRecord
|
|
564
620
|
fixtures.size
|
565
621
|
end
|
566
622
|
|
567
|
-
#
|
623
|
+
# Returns a hash of rows to be inserted. The key is the table, the value is
|
568
624
|
# a list of rows to insert to that table.
|
569
625
|
def table_rows
|
570
|
-
now =
|
571
|
-
now = now.to_s(:db)
|
626
|
+
now = config.default_timezone == :utc ? Time.now.utc : Time.now
|
572
627
|
|
573
628
|
# allow a standard key to be used for doing defaults in YAML
|
574
629
|
fixtures.delete('DEFAULTS')
|
@@ -579,22 +634,29 @@ module ActiveRecord
|
|
579
634
|
rows[table_name] = fixtures.map do |label, fixture|
|
580
635
|
row = fixture.to_hash
|
581
636
|
|
582
|
-
if model_class
|
637
|
+
if model_class
|
583
638
|
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
|
584
639
|
if model_class.record_timestamps
|
585
|
-
timestamp_column_names.each do |
|
586
|
-
row[
|
640
|
+
timestamp_column_names.each do |c_name|
|
641
|
+
row[c_name] = now unless row.key?(c_name)
|
587
642
|
end
|
588
643
|
end
|
589
644
|
|
590
645
|
# interpolate the fixture label
|
591
646
|
row.each do |key, value|
|
592
|
-
row[key] = label if value
|
647
|
+
row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
|
593
648
|
end
|
594
649
|
|
595
650
|
# generate a primary key if necessary
|
596
651
|
if has_primary_key_column? && !row.include?(primary_key_name)
|
597
|
-
row[primary_key_name] = ActiveRecord::
|
652
|
+
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
|
653
|
+
end
|
654
|
+
|
655
|
+
# Resolve enums
|
656
|
+
model_class.defined_enums.each do |name, values|
|
657
|
+
if row.include?(name)
|
658
|
+
row[name] = values.fetch(row[name], row[name])
|
659
|
+
end
|
598
660
|
end
|
599
661
|
|
600
662
|
# If STI is used, find the correct subclass for association reflection
|
@@ -605,28 +667,24 @@ module ActiveRecord
|
|
605
667
|
model_class
|
606
668
|
end
|
607
669
|
|
608
|
-
reflection_class.
|
670
|
+
reflection_class._reflections.each_value do |association|
|
609
671
|
case association.macro
|
610
672
|
when :belongs_to
|
611
673
|
# Do not replace association name with association foreign key if they are named the same
|
612
674
|
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
613
675
|
|
614
676
|
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
615
|
-
if association.
|
677
|
+
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
616
678
|
# support polymorphic belongs_to as "label (Type)"
|
617
679
|
row[association.foreign_type] = $1
|
618
680
|
end
|
619
681
|
|
620
|
-
|
682
|
+
fk_type = reflection_class.type_for_attribute(fk_name).type
|
683
|
+
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
621
684
|
end
|
622
|
-
when :
|
623
|
-
if
|
624
|
-
|
625
|
-
table_name = association.options[:join_table]
|
626
|
-
rows[table_name].concat targets.map { |target|
|
627
|
-
{ association.foreign_key => row[primary_key_name],
|
628
|
-
association.association_foreign_key => ActiveRecord::Fixtures.identify(target) }
|
629
|
-
}
|
685
|
+
when :has_many
|
686
|
+
if association.options[:through]
|
687
|
+
add_join_records(rows, row, HasManyThroughProxy.new(association))
|
630
688
|
end
|
631
689
|
end
|
632
690
|
end
|
@@ -637,11 +695,63 @@ module ActiveRecord
|
|
637
695
|
rows
|
638
696
|
end
|
639
697
|
|
698
|
+
class ReflectionProxy # :nodoc:
|
699
|
+
def initialize(association)
|
700
|
+
@association = association
|
701
|
+
end
|
702
|
+
|
703
|
+
def join_table
|
704
|
+
@association.join_table
|
705
|
+
end
|
706
|
+
|
707
|
+
def name
|
708
|
+
@association.name
|
709
|
+
end
|
710
|
+
|
711
|
+
def primary_key_type
|
712
|
+
@association.klass.type_for_attribute(@association.klass.primary_key).type
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
717
|
+
def rhs_key
|
718
|
+
@association.foreign_key
|
719
|
+
end
|
720
|
+
|
721
|
+
def lhs_key
|
722
|
+
@association.through_reflection.foreign_key
|
723
|
+
end
|
724
|
+
|
725
|
+
def join_table
|
726
|
+
@association.through_reflection.table_name
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
640
730
|
private
|
641
731
|
def primary_key_name
|
642
732
|
@primary_key_name ||= model_class && model_class.primary_key
|
643
733
|
end
|
644
734
|
|
735
|
+
def primary_key_type
|
736
|
+
@primary_key_type ||= model_class && model_class.type_for_attribute(model_class.primary_key).type
|
737
|
+
end
|
738
|
+
|
739
|
+
def add_join_records(rows, row, association)
|
740
|
+
# This is the case when the join table has no fixtures file
|
741
|
+
if (targets = row.delete(association.name.to_s))
|
742
|
+
table_name = association.join_table
|
743
|
+
column_type = association.primary_key_type
|
744
|
+
lhs_key = association.lhs_key
|
745
|
+
rhs_key = association.rhs_key
|
746
|
+
|
747
|
+
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
748
|
+
rows[table_name].concat targets.map { |target|
|
749
|
+
{ lhs_key => row[primary_key_name],
|
750
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
751
|
+
}
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
645
755
|
def has_primary_key_column?
|
646
756
|
@has_primary_key_column ||= primary_key_name &&
|
647
757
|
model_class.columns.any? { |c| c.name == primary_key_name }
|
@@ -657,25 +767,37 @@ module ActiveRecord
|
|
657
767
|
end
|
658
768
|
|
659
769
|
def column_names
|
660
|
-
@column_names ||= @connection.columns(@table_name).collect
|
770
|
+
@column_names ||= @connection.columns(@table_name).collect(&:name)
|
661
771
|
end
|
662
772
|
|
663
|
-
def
|
664
|
-
|
773
|
+
def model_class=(class_name)
|
774
|
+
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
775
|
+
@model_class = class_name
|
776
|
+
else
|
777
|
+
@model_class = class_name.safe_constantize if class_name
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
781
|
+
# Loads the fixtures from the YAML file at +path+.
|
782
|
+
# If the file sets the +model_class+ and current instance value is not set,
|
783
|
+
# it uses the file value.
|
784
|
+
def read_fixture_files(path)
|
785
|
+
yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
|
665
786
|
::File.file?(f)
|
666
|
-
} + [yaml_file_path]
|
787
|
+
} + [yaml_file_path(path)]
|
667
788
|
|
668
|
-
yaml_files.
|
669
|
-
|
670
|
-
fh.
|
671
|
-
|
789
|
+
yaml_files.each_with_object({}) do |file, fixtures|
|
790
|
+
FixtureSet::File.open(file) do |fh|
|
791
|
+
self.model_class ||= fh.model_class if fh.model_class
|
792
|
+
fh.each do |fixture_name, row|
|
793
|
+
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
672
794
|
end
|
673
795
|
end
|
674
796
|
end
|
675
797
|
end
|
676
798
|
|
677
|
-
def yaml_file_path
|
678
|
-
"#{
|
799
|
+
def yaml_file_path(path)
|
800
|
+
"#{path}.yml"
|
679
801
|
end
|
680
802
|
|
681
803
|
end
|
@@ -712,7 +834,9 @@ module ActiveRecord
|
|
712
834
|
|
713
835
|
def find
|
714
836
|
if model_class
|
715
|
-
model_class.
|
837
|
+
model_class.unscoped do
|
838
|
+
model_class.find(fixture[model_class.primary_key])
|
839
|
+
end
|
716
840
|
else
|
717
841
|
raise FixtureClassNotFound, "No class attached to find."
|
718
842
|
end
|
@@ -724,91 +848,97 @@ module ActiveRecord
|
|
724
848
|
module TestFixtures
|
725
849
|
extend ActiveSupport::Concern
|
726
850
|
|
727
|
-
|
728
|
-
|
729
|
-
|
851
|
+
def before_setup # :nodoc:
|
852
|
+
setup_fixtures
|
853
|
+
super
|
854
|
+
end
|
730
855
|
|
731
|
-
|
856
|
+
def after_teardown # :nodoc:
|
857
|
+
super
|
858
|
+
teardown_fixtures
|
859
|
+
end
|
860
|
+
|
861
|
+
included do
|
862
|
+
class_attribute :fixture_path, :instance_writer => false
|
732
863
|
class_attribute :fixture_table_names
|
733
864
|
class_attribute :fixture_class_names
|
865
|
+
class_attribute :use_transactional_tests
|
734
866
|
class_attribute :use_transactional_fixtures
|
735
|
-
class_attribute :use_instantiated_fixtures
|
867
|
+
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
|
736
868
|
class_attribute :pre_loaded_fixtures
|
869
|
+
class_attribute :config
|
870
|
+
|
871
|
+
singleton_class.deprecate 'use_transactional_fixtures=' => 'use use_transactional_tests= instead'
|
737
872
|
|
738
873
|
self.fixture_table_names = []
|
739
|
-
self.use_transactional_fixtures = true
|
740
874
|
self.use_instantiated_fixtures = false
|
741
875
|
self.pre_loaded_fixtures = false
|
876
|
+
self.config = ActiveRecord::Base
|
742
877
|
|
743
|
-
self.fixture_class_names =
|
744
|
-
|
878
|
+
self.fixture_class_names = {}
|
879
|
+
|
880
|
+
silence_warnings do
|
881
|
+
define_singleton_method :use_transactional_tests do
|
882
|
+
if use_transactional_fixtures.nil?
|
883
|
+
true
|
884
|
+
else
|
885
|
+
use_transactional_fixtures
|
886
|
+
end
|
887
|
+
end
|
745
888
|
end
|
746
889
|
end
|
747
890
|
|
748
891
|
module ClassMethods
|
892
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
893
|
+
#
|
894
|
+
# Examples:
|
895
|
+
#
|
896
|
+
# set_fixture_class some_fixture: SomeModel,
|
897
|
+
# 'namespaced/fixture' => Another::Model
|
898
|
+
#
|
899
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
749
900
|
def set_fixture_class(class_names = {})
|
750
|
-
self.fixture_class_names = self.fixture_class_names.merge(class_names)
|
901
|
+
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
|
751
902
|
end
|
752
903
|
|
753
|
-
def fixtures(*
|
754
|
-
if
|
755
|
-
|
756
|
-
|
904
|
+
def fixtures(*fixture_set_names)
|
905
|
+
if fixture_set_names.first == :all
|
906
|
+
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
|
907
|
+
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
757
908
|
else
|
758
|
-
|
909
|
+
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
759
910
|
end
|
760
911
|
|
761
|
-
self.fixture_table_names |=
|
762
|
-
|
763
|
-
setup_fixture_accessors(fixture_names)
|
764
|
-
end
|
765
|
-
|
766
|
-
def try_to_load_dependency(file_name)
|
767
|
-
require_dependency file_name
|
768
|
-
rescue LoadError => e
|
769
|
-
# Let's hope the developer has included it himself
|
770
|
-
|
771
|
-
# Let's warn in case this is a subdependency, otherwise
|
772
|
-
# subdependency error messages are totally cryptic
|
773
|
-
if ActiveRecord::Base.logger
|
774
|
-
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
775
|
-
end
|
776
|
-
end
|
777
|
-
|
778
|
-
def require_fixture_classes(fixture_names = nil)
|
779
|
-
(fixture_names || fixture_table_names).each do |fixture_name|
|
780
|
-
file_name = fixture_name.to_s
|
781
|
-
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
|
782
|
-
try_to_load_dependency(file_name)
|
783
|
-
end
|
912
|
+
self.fixture_table_names |= fixture_set_names
|
913
|
+
setup_fixture_accessors(fixture_set_names)
|
784
914
|
end
|
785
915
|
|
786
|
-
def setup_fixture_accessors(
|
787
|
-
|
916
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
917
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
788
918
|
methods = Module.new do
|
789
|
-
|
790
|
-
|
919
|
+
fixture_set_names.each do |fs_name|
|
920
|
+
fs_name = fs_name.to_s
|
921
|
+
accessor_name = fs_name.tr('/', '_').to_sym
|
791
922
|
|
792
|
-
define_method(
|
793
|
-
force_reload =
|
923
|
+
define_method(accessor_name) do |*fixture_names|
|
924
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
794
925
|
|
795
|
-
@fixture_cache[
|
926
|
+
@fixture_cache[fs_name] ||= {}
|
796
927
|
|
797
|
-
instances =
|
798
|
-
|
928
|
+
instances = fixture_names.map do |f_name|
|
929
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
930
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
799
931
|
|
800
|
-
if @loaded_fixtures[
|
801
|
-
|
802
|
-
@fixture_cache[fixture_name][fixture] ||= @loaded_fixtures[fixture_name][fixture.to_s].find
|
803
|
-
end
|
932
|
+
if @loaded_fixtures[fs_name][f_name]
|
933
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
804
934
|
else
|
805
|
-
raise StandardError, "No fixture
|
935
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
806
936
|
end
|
807
937
|
end
|
808
938
|
|
809
939
|
instances.size == 1 ? instances.first : instances
|
810
940
|
end
|
811
|
-
private
|
941
|
+
private accessor_name
|
812
942
|
end
|
813
943
|
end
|
814
944
|
include methods
|
@@ -816,7 +946,7 @@ module ActiveRecord
|
|
816
946
|
|
817
947
|
def uses_transaction(*methods)
|
818
948
|
@uses_transaction = [] unless defined?(@uses_transaction)
|
819
|
-
@uses_transaction.concat methods.map
|
949
|
+
@uses_transaction.concat methods.map(&:to_s)
|
820
950
|
end
|
821
951
|
|
822
952
|
def uses_transaction?(method)
|
@@ -826,15 +956,13 @@ module ActiveRecord
|
|
826
956
|
end
|
827
957
|
|
828
958
|
def run_in_transaction?
|
829
|
-
|
959
|
+
use_transactional_tests &&
|
830
960
|
!self.class.uses_transaction?(method_name)
|
831
961
|
end
|
832
962
|
|
833
|
-
def setup_fixtures
|
834
|
-
|
835
|
-
|
836
|
-
if pre_loaded_fixtures && !use_transactional_fixtures
|
837
|
-
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
963
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
964
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
965
|
+
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_tests'
|
838
966
|
end
|
839
967
|
|
840
968
|
@fixture_cache = {}
|
@@ -846,20 +974,18 @@ module ActiveRecord
|
|
846
974
|
if @@already_loaded_fixtures[self.class]
|
847
975
|
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
848
976
|
else
|
849
|
-
@loaded_fixtures = load_fixtures
|
977
|
+
@loaded_fixtures = load_fixtures(config)
|
850
978
|
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
851
979
|
end
|
852
980
|
@fixture_connections = enlist_fixture_connections
|
853
981
|
@fixture_connections.each do |connection|
|
854
|
-
connection.
|
855
|
-
connection.transaction_joinable = false
|
856
|
-
connection.begin_db_transaction
|
982
|
+
connection.begin_transaction joinable: false
|
857
983
|
end
|
858
984
|
# Load fixtures for every test.
|
859
985
|
else
|
860
|
-
ActiveRecord::
|
986
|
+
ActiveRecord::FixtureSet.reset_cache
|
861
987
|
@@already_loaded_fixtures[self.class] = nil
|
862
|
-
@loaded_fixtures = load_fixtures
|
988
|
+
@loaded_fixtures = load_fixtures(config)
|
863
989
|
end
|
864
990
|
|
865
991
|
# Instantiate fixtures for every test if requested.
|
@@ -867,50 +993,37 @@ module ActiveRecord
|
|
867
993
|
end
|
868
994
|
|
869
995
|
def teardown_fixtures
|
870
|
-
return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
|
871
|
-
|
872
|
-
unless run_in_transaction?
|
873
|
-
ActiveRecord::Fixtures.reset_cache
|
874
|
-
end
|
875
|
-
|
876
996
|
# Rollback changes if a transaction is active.
|
877
997
|
if run_in_transaction?
|
878
998
|
@fixture_connections.each do |connection|
|
879
|
-
if connection.
|
880
|
-
connection.rollback_db_transaction
|
881
|
-
connection.decrement_open_transactions
|
882
|
-
end
|
999
|
+
connection.rollback_transaction if connection.transaction_open?
|
883
1000
|
end
|
884
1001
|
@fixture_connections.clear
|
1002
|
+
else
|
1003
|
+
ActiveRecord::FixtureSet.reset_cache
|
885
1004
|
end
|
1005
|
+
|
886
1006
|
ActiveRecord::Base.clear_active_connections!
|
887
1007
|
end
|
888
1008
|
|
889
1009
|
def enlist_fixture_connections
|
890
|
-
ActiveRecord::Base.connection_handler.
|
1010
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
891
1011
|
end
|
892
1012
|
|
893
1013
|
private
|
894
|
-
def load_fixtures
|
895
|
-
fixtures = ActiveRecord::
|
1014
|
+
def load_fixtures(config)
|
1015
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
896
1016
|
Hash[fixtures.map { |f| [f.name, f] }]
|
897
1017
|
end
|
898
1018
|
|
899
|
-
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
|
900
|
-
@@required_fixture_classes = false
|
901
|
-
|
902
1019
|
def instantiate_fixtures
|
903
1020
|
if pre_loaded_fixtures
|
904
|
-
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::
|
905
|
-
|
906
|
-
self.class.require_fixture_classes ActiveRecord::Fixtures.all_loaded_fixtures.keys
|
907
|
-
@@required_fixture_classes = true
|
908
|
-
end
|
909
|
-
ActiveRecord::Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
|
1021
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
1022
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
910
1023
|
else
|
911
1024
|
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
912
1025
|
@loaded_fixtures.each_value do |fixture_set|
|
913
|
-
ActiveRecord::
|
1026
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
914
1027
|
end
|
915
1028
|
end
|
916
1029
|
end
|
@@ -920,3 +1033,13 @@ module ActiveRecord
|
|
920
1033
|
end
|
921
1034
|
end
|
922
1035
|
end
|
1036
|
+
|
1037
|
+
class ActiveRecord::FixtureSet::RenderContext # :nodoc:
|
1038
|
+
def self.create_subclass
|
1039
|
+
Class.new ActiveRecord::FixtureSet.context_class do
|
1040
|
+
def get_binding
|
1041
|
+
binding()
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
end
|