activerecord 3.0.0 → 4.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.

Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +35 -44
  5. data/examples/performance.rb +110 -100
  6. data/lib/active_record/aggregations.rb +59 -75
  7. data/lib/active_record/associations/alias_tracker.rb +76 -0
  8. data/lib/active_record/associations/association.rb +248 -0
  9. data/lib/active_record/associations/association_scope.rb +135 -0
  10. data/lib/active_record/associations/belongs_to_association.rb +60 -59
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
  12. data/lib/active_record/associations/builder/association.rb +108 -0
  13. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  14. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  16. data/lib/active_record/associations/builder/has_many.rb +15 -0
  17. data/lib/active_record/associations/builder/has_one.rb +25 -0
  18. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  19. data/lib/active_record/associations/collection_association.rb +608 -0
  20. data/lib/active_record/associations/collection_proxy.rb +986 -0
  21. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
  22. data/lib/active_record/associations/has_many_association.rb +83 -76
  23. data/lib/active_record/associations/has_many_through_association.rb +147 -66
  24. data/lib/active_record/associations/has_one_association.rb +67 -108
  25. data/lib/active_record/associations/has_one_through_association.rb +21 -25
  26. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  27. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  28. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  29. data/lib/active_record/associations/join_dependency.rb +235 -0
  30. data/lib/active_record/associations/join_helper.rb +45 -0
  31. data/lib/active_record/associations/preloader/association.rb +121 -0
  32. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  33. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  35. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  36. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  37. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  38. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  39. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  40. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  41. data/lib/active_record/associations/preloader.rb +178 -0
  42. data/lib/active_record/associations/singular_association.rb +64 -0
  43. data/lib/active_record/associations/through_association.rb +87 -0
  44. data/lib/active_record/associations.rb +512 -1224
  45. data/lib/active_record/attribute_assignment.rb +201 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
  47. data/lib/active_record/attribute_methods/dirty.rb +51 -28
  48. data/lib/active_record/attribute_methods/primary_key.rb +94 -22
  49. data/lib/active_record/attribute_methods/query.rb +5 -4
  50. data/lib/active_record/attribute_methods/read.rb +63 -72
  51. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
  53. data/lib/active_record/attribute_methods/write.rb +39 -13
  54. data/lib/active_record/attribute_methods.rb +362 -29
  55. data/lib/active_record/autosave_association.rb +132 -75
  56. data/lib/active_record/base.rb +83 -1627
  57. data/lib/active_record/callbacks.rb +69 -47
  58. data/lib/active_record/coders/yaml_column.rb +38 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  70. data/lib/active_record/connection_adapters/column.rb +318 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
  74. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  75. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
  82. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
  84. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  85. data/lib/active_record/connection_handling.rb +98 -0
  86. data/lib/active_record/core.rb +463 -0
  87. data/lib/active_record/counter_cache.rb +108 -101
  88. data/lib/active_record/dynamic_matchers.rb +131 -0
  89. data/lib/active_record/errors.rb +54 -13
  90. data/lib/active_record/explain.rb +38 -0
  91. data/lib/active_record/explain_registry.rb +30 -0
  92. data/lib/active_record/explain_subscriber.rb +29 -0
  93. data/lib/active_record/fixture_set/file.rb +55 -0
  94. data/lib/active_record/fixtures.rb +703 -785
  95. data/lib/active_record/inheritance.rb +200 -0
  96. data/lib/active_record/integration.rb +60 -0
  97. data/lib/active_record/locale/en.yml +8 -1
  98. data/lib/active_record/locking/optimistic.rb +69 -60
  99. data/lib/active_record/locking/pessimistic.rb +34 -12
  100. data/lib/active_record/log_subscriber.rb +40 -6
  101. data/lib/active_record/migration/command_recorder.rb +164 -0
  102. data/lib/active_record/migration/join_table.rb +15 -0
  103. data/lib/active_record/migration.rb +614 -216
  104. data/lib/active_record/model_schema.rb +345 -0
  105. data/lib/active_record/nested_attributes.rb +248 -119
  106. data/lib/active_record/null_relation.rb +65 -0
  107. data/lib/active_record/persistence.rb +275 -57
  108. data/lib/active_record/query_cache.rb +29 -9
  109. data/lib/active_record/querying.rb +62 -0
  110. data/lib/active_record/railtie.rb +135 -21
  111. data/lib/active_record/railties/console_sandbox.rb +5 -0
  112. data/lib/active_record/railties/controller_runtime.rb +17 -5
  113. data/lib/active_record/railties/databases.rake +249 -359
  114. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  115. data/lib/active_record/readonly_attributes.rb +30 -0
  116. data/lib/active_record/reflection.rb +283 -103
  117. data/lib/active_record/relation/batches.rb +38 -34
  118. data/lib/active_record/relation/calculations.rb +252 -139
  119. data/lib/active_record/relation/delegation.rb +125 -0
  120. data/lib/active_record/relation/finder_methods.rb +182 -188
  121. data/lib/active_record/relation/merger.rb +161 -0
  122. data/lib/active_record/relation/predicate_builder.rb +86 -21
  123. data/lib/active_record/relation/query_methods.rb +917 -134
  124. data/lib/active_record/relation/spawn_methods.rb +53 -92
  125. data/lib/active_record/relation.rb +405 -143
  126. data/lib/active_record/result.rb +67 -0
  127. data/lib/active_record/runtime_registry.rb +17 -0
  128. data/lib/active_record/sanitization.rb +168 -0
  129. data/lib/active_record/schema.rb +20 -14
  130. data/lib/active_record/schema_dumper.rb +55 -46
  131. data/lib/active_record/schema_migration.rb +39 -0
  132. data/lib/active_record/scoping/default.rb +146 -0
  133. data/lib/active_record/scoping/named.rb +175 -0
  134. data/lib/active_record/scoping.rb +82 -0
  135. data/lib/active_record/serialization.rb +8 -46
  136. data/lib/active_record/serializers/xml_serializer.rb +21 -68
  137. data/lib/active_record/statement_cache.rb +26 -0
  138. data/lib/active_record/store.rb +156 -0
  139. data/lib/active_record/tasks/database_tasks.rb +203 -0
  140. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  141. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  142. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  143. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  144. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  145. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  146. data/lib/active_record/test_case.rb +57 -28
  147. data/lib/active_record/timestamp.rb +49 -18
  148. data/lib/active_record/transactions.rb +106 -63
  149. data/lib/active_record/translation.rb +22 -0
  150. data/lib/active_record/validations/associated.rb +25 -24
  151. data/lib/active_record/validations/presence.rb +65 -0
  152. data/lib/active_record/validations/uniqueness.rb +123 -83
  153. data/lib/active_record/validations.rb +29 -29
  154. data/lib/active_record/version.rb +7 -5
  155. data/lib/active_record.rb +83 -34
  156. data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
  157. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  158. data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
  159. data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
  160. data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
  161. data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
  162. data/lib/rails/generators/active_record.rb +4 -8
  163. metadata +163 -121
  164. data/CHANGELOG +0 -6023
  165. data/examples/associations.png +0 -0
  166. data/lib/active_record/association_preload.rb +0 -403
  167. data/lib/active_record/associations/association_collection.rb +0 -562
  168. data/lib/active_record/associations/association_proxy.rb +0 -295
  169. data/lib/active_record/associations/through_association_scope.rb +0 -154
  170. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
  171. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
  172. data/lib/active_record/dynamic_finder_match.rb +0 -53
  173. data/lib/active_record/dynamic_scope_match.rb +0 -32
  174. data/lib/active_record/named_scope.rb +0 -138
  175. data/lib/active_record/observer.rb +0 -140
  176. data/lib/active_record/session_store.rb +0 -340
  177. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
  178. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  179. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
  180. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
  181. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,534 +1,492 @@
1
1
  require 'erb'
2
2
  require 'yaml'
3
- require 'csv'
4
3
  require 'zlib'
5
4
  require 'active_support/dependencies'
6
- require 'active_support/core_ext/array/wrap'
7
- require 'active_support/core_ext/object/blank'
8
- require 'active_support/core_ext/logger'
5
+ require 'active_record/fixture_set/file'
6
+ require 'active_record/errors'
9
7
 
10
- if RUBY_VERSION < '1.9'
11
- module YAML #:nodoc:
12
- class Omap #:nodoc:
13
- def keys; map { |k, v| k } end
14
- def values; map { |k, v| v } end
15
- end
16
- end
17
- end
18
-
19
- if defined? ActiveRecord
8
+ module ActiveRecord
20
9
  class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
21
10
  end
22
- else
23
- class FixtureClassNotFound < StandardError #:nodoc:
24
- end
25
- end
26
11
 
27
- class FixturesFileNotFound < StandardError; end
28
-
29
- # Fixtures are a way of organizing data that you want to test against; in short, sample data.
30
- #
31
- # = Fixture formats
32
- #
33
- # Fixtures come in 3 flavors:
34
- #
35
- # 1. YAML fixtures
36
- # 2. CSV fixtures
37
- # 3. Single-file fixtures
38
- #
39
- # == YAML fixtures
40
- #
41
- # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
42
- # in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
43
- #
44
- # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed
45
- # in the directory appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is
46
- # automatically configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
47
- # The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
48
- # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a YAML fixture file looks like this:
49
- #
50
- # rubyonrails:
51
- # id: 1
52
- # name: Ruby on Rails
53
- # url: http://www.rubyonrails.org
54
- #
55
- # google:
56
- # id: 2
57
- # name: Google
58
- # url: http://www.google.com
59
- #
60
- # This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
61
- # indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
62
- # pleasure.
63
- #
64
- # Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
65
- # See http://yaml.org/type/omap.html
66
- # for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
67
- # This is commonly needed for tree structures. Example:
68
- #
69
- # --- !omap
70
- # - parent:
71
- # id: 1
72
- # parent_id: NULL
73
- # title: Parent
74
- # - child:
75
- # id: 2
76
- # parent_id: 1
77
- # title: Child
78
- #
79
- # == CSV fixtures
80
- #
81
- # Fixtures can also be kept in the Comma Separated Value (CSV) format. Akin to YAML fixtures, CSV fixtures are stored
82
- # in a single file, but instead end with the <tt>.csv</tt> file extension
83
- # (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>).
84
- #
85
- # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
86
- # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the
87
- # file is then comprised
88
- # of the actual data (1 per line). Here's an example:
89
- #
90
- # id, name, url
91
- # 1, Ruby On Rails, http://www.rubyonrails.org
92
- # 2, Google, http://www.google.com
93
- #
94
- # Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
95
- # need to use a double quote character, you must escape it with another double quote.
96
- #
97
- # Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
98
- # fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
99
- # number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
100
- # "web_site_2".
101
- #
102
- # Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
103
- # have existing data somewhere already.
104
- #
105
- # == Single-file fixtures
106
- #
107
- # This type of fixture was the original format for Active Record that has since been deprecated in
108
- # favor of the YAML and CSV formats.
109
- # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model)
110
- # to the directory appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
111
- # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/<your-model-name>/</tt> --
112
- # like <tt><your-rails-app>/test/fixtures/web_sites/</tt> for the WebSite model).
113
- #
114
- # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
115
- # extensions, but if you are on a Windows machine, you might consider adding <tt>.txt</tt> as the extension.
116
- # Here's what the above example might look like:
117
- #
118
- # web_sites/google
119
- # web_sites/yahoo.txt
120
- # web_sites/ruby-on-rails
121
- #
122
- # The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
123
- # of "name => value". Here's an example of the ruby-on-rails fixture above:
124
- #
125
- # id => 1
126
- # name => Ruby on Rails
127
- # url => http://www.rubyonrails.org
128
- #
129
- # = Using fixtures in testcases
130
- #
131
- # Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
132
- # fixtures, but first let's take a look at a sample unit test:
133
- #
134
- # require 'test_helper'
135
- #
136
- # class WebSiteTest < ActiveSupport::TestCase
137
- # test "web_site_count" do
138
- # assert_equal 2, WebSite.count
139
- # end
140
- # end
141
- #
142
- # By default, the <tt>test_helper module</tt> will load all of your fixtures into your test database,
143
- # so this test will succeed.
144
- # The testing environment will automatically load the all fixtures into the database before each test.
145
- # To ensure consistent data, the environment deletes the fixtures before running the load.
146
- #
147
- # In addition to being available in the database, the fixture's data may also be accessed by
148
- # using a special dynamic method, which has the same name as the model, and accepts the
149
- # name of the fixture to instantiate:
150
- #
151
- # test "find" do
152
- # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
153
- # end
154
- #
155
- # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the following tests:
156
- #
157
- # test "find_alt_method_1" do
158
- # assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
159
- # end
160
- #
161
- # test "find_alt_method_2" do
162
- # assert_equal "Ruby on Rails", @rubyonrails.news
163
- # end
164
- #
165
- # In order to use these methods to access fixtured data within your testcases, you must specify one of the
166
- # following in your <tt>ActiveSupport::TestCase</tt>-derived class:
167
- #
168
- # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
169
- # self.use_instantiated_fixtures = true
170
- #
171
- # - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
172
- # self.use_instantiated_fixtures = :no_instances
173
- #
174
- # Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
175
- # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
176
- # large sets of fixtured data.
177
- #
178
- # = Dynamic fixtures with ERb
179
- #
180
- # Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
181
- # mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
182
- #
183
- # <% for i in 1..1000 %>
184
- # fix_<%= i %>:
185
- # id: <%= i %>
186
- # name: guy_<%= 1 %>
187
- # <% end %>
188
- #
189
- # This will create 1000 very simple YAML fixtures.
190
- #
191
- # Using ERb, you can also inject dynamic values into your fixtures with inserts like <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
192
- # This is however a feature to be used with some caution. The point of fixtures are that they're
193
- # stable units of predictable sample data. If you feel that you need to inject dynamic values, then
194
- # perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
195
- # in fixtures are to be considered a code smell.
196
- #
197
- # = Transactional fixtures
198
- #
199
- # TestCases can use begin+rollback to isolate their changes to the database instead of having to
200
- # delete+insert for every test case.
201
- #
202
- # class FooTest < ActiveSupport::TestCase
203
- # self.use_transactional_fixtures = true
204
- #
205
- # test "godzilla" do
206
- # assert !Foo.find(:all).empty?
207
- # Foo.destroy_all
208
- # assert Foo.find(:all).empty?
209
- # end
210
- #
211
- # test "godzilla aftermath" do
212
- # assert !Foo.find(:all).empty?
213
- # end
214
- # end
215
- #
216
- # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
217
- # then you may omit all fixtures declarations in your test cases since all the data's already there
218
- # and every case rolls back its changes.
219
- #
220
- # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
221
- # access to fixture data for every table that has been loaded through fixtures (depending on the
222
- # value of +use_instantiated_fixtures+)
223
- #
224
- # When *not* to use transactional fixtures:
225
- #
226
- # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
227
- # all parent transactions commit, particularly, the fixtures transaction which is begun in setup
228
- # and rolled back in teardown. Thus, you won't be able to verify
229
- # the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
230
- # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
231
- # Use InnoDB, MaxDB, or NDB instead.
232
- #
233
- # = Advanced YAML Fixtures
234
- #
235
- # YAML fixtures that don't specify an ID get some extra features:
236
- #
237
- # * Stable, autogenerated IDs
238
- # * Label references for associations (belongs_to, has_one, has_many)
239
- # * HABTM associations as inline lists
240
- # * Autofilled timestamp columns
241
- # * Fixture label interpolation
242
- # * Support for YAML defaults
243
- #
244
- # == Stable, autogenerated IDs
245
- #
246
- # Here, have a monkey fixture:
247
- #
248
- # george:
249
- # id: 1
250
- # name: George the Monkey
251
- #
252
- # reginald:
253
- # id: 2
254
- # name: Reginald the Pirate
255
- #
256
- # Each of these fixtures has two unique identifiers: one for the database
257
- # and one for the humans. Why don't we generate the primary key instead?
258
- # Hashing each fixture's label yields a consistent ID:
259
- #
260
- # george: # generated id: 503576764
261
- # name: George the Monkey
262
- #
263
- # reginald: # generated id: 324201669
264
- # name: Reginald the Pirate
265
- #
266
- # Active Record looks at the fixture's model class, discovers the correct
267
- # primary key, and generates it right before inserting the fixture
268
- # into the database.
269
- #
270
- # The generated ID for a given label is constant, so we can discover
271
- # any fixture's ID without loading anything, as long as we know the label.
272
- #
273
- # == Label references for associations (belongs_to, has_one, has_many)
274
- #
275
- # Specifying foreign keys in fixtures can be very fragile, not to
276
- # mention difficult to read. Since Active Record can figure out the ID of
277
- # any fixture from its label, you can specify FK's by label instead of ID.
278
- #
279
- # === belongs_to
280
- #
281
- # Let's break out some more monkeys and pirates.
282
- #
283
- # ### in pirates.yml
284
- #
285
- # reginald:
286
- # id: 1
287
- # name: Reginald the Pirate
288
- # monkey_id: 1
289
- #
290
- # ### in monkeys.yml
291
- #
292
- # george:
293
- # id: 1
294
- # name: George the Monkey
295
- # pirate_id: 1
296
- #
297
- # Add a few more monkeys and pirates and break this into multiple files,
298
- # and it gets pretty hard to keep track of what's going on. Let's
299
- # use labels instead of IDs:
300
- #
301
- # ### in pirates.yml
302
- #
303
- # reginald:
304
- # name: Reginald the Pirate
305
- # monkey: george
306
- #
307
- # ### in monkeys.yml
308
- #
309
- # george:
310
- # name: George the Monkey
311
- # pirate: reginald
312
- #
313
- # Pow! All is made clear. Active Record reflects on the fixture's model class,
314
- # finds all the +belongs_to+ associations, and allows you to specify
315
- # a target *label* for the *association* (monkey: george) rather than
316
- # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
317
- #
318
- # ==== Polymorphic belongs_to
319
- #
320
- # Supporting polymorphic relationships is a little bit more complicated, since
321
- # Active Record needs to know what type your association is pointing at. Something
322
- # like this should look familiar:
323
- #
324
- # ### in fruit.rb
325
- #
326
- # belongs_to :eater, :polymorphic => true
327
- #
328
- # ### in fruits.yml
329
- #
330
- # apple:
331
- # id: 1
332
- # name: apple
333
- # eater_id: 1
334
- # eater_type: Monkey
335
- #
336
- # Can we do better? You bet!
337
- #
338
- # apple:
339
- # eater: george (Monkey)
340
- #
341
- # Just provide the polymorphic target type and Active Record will take care of the rest.
342
- #
343
- # === has_and_belongs_to_many
344
- #
345
- # Time to give our monkey some fruit.
346
- #
347
- # ### in monkeys.yml
348
- #
349
- # george:
350
- # id: 1
351
- # name: George the Monkey
352
- #
353
- # ### in fruits.yml
354
- #
355
- # apple:
356
- # id: 1
357
- # name: apple
358
- #
359
- # orange:
360
- # id: 2
361
- # name: orange
362
- #
363
- # grape:
364
- # id: 3
365
- # name: grape
366
- #
367
- # ### in fruits_monkeys.yml
368
- #
369
- # apple_george:
370
- # fruit_id: 1
371
- # monkey_id: 1
372
- #
373
- # orange_george:
374
- # fruit_id: 2
375
- # monkey_id: 1
376
- #
377
- # grape_george:
378
- # fruit_id: 3
379
- # monkey_id: 1
380
- #
381
- # Let's make the HABTM fixture go away.
382
- #
383
- # ### in monkeys.yml
384
- #
385
- # george:
386
- # id: 1
387
- # name: George the Monkey
388
- # fruits: apple, orange, grape
389
- #
390
- # ### in fruits.yml
391
- #
392
- # apple:
393
- # name: apple
394
- #
395
- # orange:
396
- # name: orange
397
- #
398
- # grape:
399
- # name: grape
400
- #
401
- # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
402
- # on George's fixture, but we could've just as easily specified a list
403
- # of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
404
- # the fixture's model class and discovers the +has_and_belongs_to_many+
405
- # associations.
406
- #
407
- # == Autofilled timestamp columns
408
- #
409
- # If your table/model specifies any of Active Record's
410
- # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
411
- # they will automatically be set to <tt>Time.now</tt>.
412
- #
413
- # If you've set specific values, they'll be left alone.
414
- #
415
- # == Fixture label interpolation
416
- #
417
- # The label of the current fixture is always available as a column value:
418
- #
419
- # geeksomnia:
420
- # name: Geeksomnia's Account
421
- # subdomain: $LABEL
422
- #
423
- # Also, sometimes (like when porting older join table fixtures) you'll need
424
- # to be able to get a hold of the identifier for a given label. ERB
425
- # to the rescue:
426
- #
427
- # george_reginald:
428
- # monkey_id: <%= Fixtures.identify(:reginald) %>
429
- # pirate_id: <%= Fixtures.identify(:george) %>
430
- #
431
- # == Support for YAML defaults
432
- #
433
- # You probably already know how to use YAML to set and reuse defaults in
434
- # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
435
- #
436
- # DEFAULTS: &DEFAULTS
437
- # created_on: <%= 3.weeks.ago.to_s(:db) %>
438
- #
439
- # first:
440
- # name: Smurf
441
- # <<: *DEFAULTS
442
- #
443
- # second:
444
- # name: Fraggle
445
- # <<: *DEFAULTS
446
- #
447
- # Any fixture labeled "DEFAULTS" is safely ignored.
448
-
449
- class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
450
- MAX_ID = 2 ** 30 - 1
451
- DEFAULT_FILTER_RE = /\.ya?ml$/
452
-
453
- @@all_cached_fixtures = {}
454
-
455
- def self.reset_cache(connection = nil)
456
- connection ||= ActiveRecord::Base.connection
457
- @@all_cached_fixtures[connection.object_id] = {}
458
- end
12
+ # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
13
+ #
14
+ # They are stored in YAML files, one file per model, which are placed in the directory
15
+ # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
16
+ # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
17
+ # The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
18
+ # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a fixture file looks
19
+ # like this:
20
+ #
21
+ # rubyonrails:
22
+ # id: 1
23
+ # name: Ruby on Rails
24
+ # url: http://www.rubyonrails.org
25
+ #
26
+ # google:
27
+ # id: 2
28
+ # name: Google
29
+ # url: http://www.google.com
30
+ #
31
+ # This fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and
32
+ # is followed by an indented list of key/value pairs in the "key: value" format. Records are
33
+ # separated by a blank line for your viewing pleasure.
34
+ #
35
+ # Note that fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
36
+ # See http://yaml.org/type/omap.html
37
+ # for the specification. You will need ordered fixtures when you have foreign key constraints
38
+ # on keys in the same table. This is commonly needed for tree structures. Example:
39
+ #
40
+ # --- !omap
41
+ # - parent:
42
+ # id: 1
43
+ # parent_id: NULL
44
+ # title: Parent
45
+ # - child:
46
+ # id: 2
47
+ # parent_id: 1
48
+ # title: Child
49
+ #
50
+ # = Using Fixtures in Test Cases
51
+ #
52
+ # Since fixtures are a testing construct, we use them in our unit and functional tests. There
53
+ # are two ways to use the fixtures, but first let's take a look at a sample unit test:
54
+ #
55
+ # require 'test_helper'
56
+ #
57
+ # class WebSiteTest < ActiveSupport::TestCase
58
+ # test "web_site_count" do
59
+ # assert_equal 2, WebSite.count
60
+ # end
61
+ # end
62
+ #
63
+ # By default, <tt>test_helper.rb</tt> will load all of your fixtures into your test database,
64
+ # so this test will succeed.
65
+ #
66
+ # The testing environment will automatically load the all fixtures into the database before each
67
+ # test. To ensure consistent data, the environment deletes the fixtures before running the load.
68
+ #
69
+ # In addition to being available in the database, the fixture's data may also be accessed by
70
+ # using a special dynamic method, which has the same name as the model, and accepts the
71
+ # name of the fixture to instantiate:
72
+ #
73
+ # test "find" do
74
+ # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
75
+ # end
76
+ #
77
+ # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
78
+ # following tests:
79
+ #
80
+ # test "find_alt_method_1" do
81
+ # assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
82
+ # end
83
+ #
84
+ # test "find_alt_method_2" do
85
+ # assert_equal "Ruby on Rails", @rubyonrails.name
86
+ # end
87
+ #
88
+ # In order to use these methods to access fixtured data within your testcases, you must specify one of the
89
+ # following in your <tt>ActiveSupport::TestCase</tt>-derived class:
90
+ #
91
+ # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
92
+ # self.use_instantiated_fixtures = true
93
+ #
94
+ # - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
95
+ # self.use_instantiated_fixtures = :no_instances
96
+ #
97
+ # Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
98
+ # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
99
+ # large sets of fixtured data.
100
+ #
101
+ # = Dynamic fixtures with ERB
102
+ #
103
+ # Some times you don't care about the content of the fixtures as much as you care about the volume.
104
+ # In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
105
+ # testing, like:
106
+ #
107
+ # <% 1.upto(1000) do |i| %>
108
+ # fix_<%= i %>:
109
+ # id: <%= i %>
110
+ # name: guy_<%= 1 %>
111
+ # <% end %>
112
+ #
113
+ # This will create 1000 very simple fixtures.
114
+ #
115
+ # Using ERB, you can also inject dynamic values into your fixtures with inserts like
116
+ # <tt><%= Date.today.strftime("%Y-%m-%d") %></tt>.
117
+ # This is however a feature to be used with some caution. The point of fixtures are that they're
118
+ # stable units of predictable sample data. If you feel that you need to inject dynamic values, then
119
+ # perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
120
+ # in fixtures are to be considered a code smell.
121
+ #
122
+ # = Transactional Fixtures
123
+ #
124
+ # Test cases can use begin+rollback to isolate their changes to the database instead of having to
125
+ # delete+insert for every test case.
126
+ #
127
+ # class FooTest < ActiveSupport::TestCase
128
+ # self.use_transactional_fixtures = true
129
+ #
130
+ # test "godzilla" do
131
+ # assert !Foo.all.empty?
132
+ # Foo.destroy_all
133
+ # assert Foo.all.empty?
134
+ # end
135
+ #
136
+ # test "godzilla aftermath" do
137
+ # assert !Foo.all.empty?
138
+ # end
139
+ # end
140
+ #
141
+ # If you preload your test database with all fixture data (probably in the rake task) and use
142
+ # transactional fixtures, then you may omit all fixtures declarations in your test cases since
143
+ # all the data's already there and every case rolls back its changes.
144
+ #
145
+ # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
146
+ # true. This will provide access to fixture data for every table that has been loaded through
147
+ # fixtures (depending on the value of +use_instantiated_fixtures+).
148
+ #
149
+ # When *not* to use transactional fixtures:
150
+ #
151
+ # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
152
+ # all parent transactions commit, particularly, the fixtures transaction which is begun in setup
153
+ # and rolled back in teardown. Thus, you won't be able to verify
154
+ # the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
155
+ # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
156
+ # Use InnoDB, MaxDB, or NDB instead.
157
+ #
158
+ # = Advanced Fixtures
159
+ #
160
+ # Fixtures that don't specify an ID get some extra features:
161
+ #
162
+ # * Stable, autogenerated IDs
163
+ # * Label references for associations (belongs_to, has_one, has_many)
164
+ # * HABTM associations as inline lists
165
+ # * Autofilled timestamp columns
166
+ # * Fixture label interpolation
167
+ # * Support for YAML defaults
168
+ #
169
+ # == Stable, Autogenerated IDs
170
+ #
171
+ # Here, have a monkey fixture:
172
+ #
173
+ # george:
174
+ # id: 1
175
+ # name: George the Monkey
176
+ #
177
+ # reginald:
178
+ # id: 2
179
+ # name: Reginald the Pirate
180
+ #
181
+ # Each of these fixtures has two unique identifiers: one for the database
182
+ # and one for the humans. Why don't we generate the primary key instead?
183
+ # Hashing each fixture's label yields a consistent ID:
184
+ #
185
+ # george: # generated id: 503576764
186
+ # name: George the Monkey
187
+ #
188
+ # reginald: # generated id: 324201669
189
+ # name: Reginald the Pirate
190
+ #
191
+ # Active Record looks at the fixture's model class, discovers the correct
192
+ # primary key, and generates it right before inserting the fixture
193
+ # into the database.
194
+ #
195
+ # The generated ID for a given label is constant, so we can discover
196
+ # any fixture's ID without loading anything, as long as we know the label.
197
+ #
198
+ # == Label references for associations (belongs_to, has_one, has_many)
199
+ #
200
+ # Specifying foreign keys in fixtures can be very fragile, not to
201
+ # mention difficult to read. Since Active Record can figure out the ID of
202
+ # any fixture from its label, you can specify FK's by label instead of ID.
203
+ #
204
+ # === belongs_to
205
+ #
206
+ # Let's break out some more monkeys and pirates.
207
+ #
208
+ # ### in pirates.yml
209
+ #
210
+ # reginald:
211
+ # id: 1
212
+ # name: Reginald the Pirate
213
+ # monkey_id: 1
214
+ #
215
+ # ### in monkeys.yml
216
+ #
217
+ # george:
218
+ # id: 1
219
+ # name: George the Monkey
220
+ # pirate_id: 1
221
+ #
222
+ # Add a few more monkeys and pirates and break this into multiple files,
223
+ # and it gets pretty hard to keep track of what's going on. Let's
224
+ # use labels instead of IDs:
225
+ #
226
+ # ### in pirates.yml
227
+ #
228
+ # reginald:
229
+ # name: Reginald the Pirate
230
+ # monkey: george
231
+ #
232
+ # ### in monkeys.yml
233
+ #
234
+ # george:
235
+ # name: George the Monkey
236
+ # pirate: reginald
237
+ #
238
+ # Pow! All is made clear. Active Record reflects on the fixture's model class,
239
+ # finds all the +belongs_to+ associations, and allows you to specify
240
+ # a target *label* for the *association* (monkey: george) rather than
241
+ # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
242
+ #
243
+ # ==== Polymorphic belongs_to
244
+ #
245
+ # Supporting polymorphic relationships is a little bit more complicated, since
246
+ # Active Record needs to know what type your association is pointing at. Something
247
+ # like this should look familiar:
248
+ #
249
+ # ### in fruit.rb
250
+ #
251
+ # belongs_to :eater, polymorphic: true
252
+ #
253
+ # ### in fruits.yml
254
+ #
255
+ # apple:
256
+ # id: 1
257
+ # name: apple
258
+ # eater_id: 1
259
+ # eater_type: Monkey
260
+ #
261
+ # Can we do better? You bet!
262
+ #
263
+ # apple:
264
+ # eater: george (Monkey)
265
+ #
266
+ # Just provide the polymorphic target type and Active Record will take care of the rest.
267
+ #
268
+ # === has_and_belongs_to_many
269
+ #
270
+ # Time to give our monkey some fruit.
271
+ #
272
+ # ### in monkeys.yml
273
+ #
274
+ # george:
275
+ # id: 1
276
+ # name: George the Monkey
277
+ #
278
+ # ### in fruits.yml
279
+ #
280
+ # apple:
281
+ # id: 1
282
+ # name: apple
283
+ #
284
+ # orange:
285
+ # id: 2
286
+ # name: orange
287
+ #
288
+ # grape:
289
+ # id: 3
290
+ # name: grape
291
+ #
292
+ # ### in fruits_monkeys.yml
293
+ #
294
+ # apple_george:
295
+ # fruit_id: 1
296
+ # monkey_id: 1
297
+ #
298
+ # orange_george:
299
+ # fruit_id: 2
300
+ # monkey_id: 1
301
+ #
302
+ # grape_george:
303
+ # fruit_id: 3
304
+ # monkey_id: 1
305
+ #
306
+ # Let's make the HABTM fixture go away.
307
+ #
308
+ # ### in monkeys.yml
309
+ #
310
+ # george:
311
+ # id: 1
312
+ # name: George the Monkey
313
+ # fruits: apple, orange, grape
314
+ #
315
+ # ### in fruits.yml
316
+ #
317
+ # apple:
318
+ # name: apple
319
+ #
320
+ # orange:
321
+ # name: orange
322
+ #
323
+ # grape:
324
+ # name: grape
325
+ #
326
+ # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
327
+ # on George's fixture, but we could've just as easily specified a list
328
+ # of monkeys on each fruit. As with +belongs_to+, Active Record reflects on
329
+ # the fixture's model class and discovers the +has_and_belongs_to_many+
330
+ # associations.
331
+ #
332
+ # == Autofilled Timestamp Columns
333
+ #
334
+ # If your table/model specifies any of Active Record's
335
+ # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
336
+ # they will automatically be set to <tt>Time.now</tt>.
337
+ #
338
+ # If you've set specific values, they'll be left alone.
339
+ #
340
+ # == Fixture label interpolation
341
+ #
342
+ # The label of the current fixture is always available as a column value:
343
+ #
344
+ # geeksomnia:
345
+ # name: Geeksomnia's Account
346
+ # subdomain: $LABEL
347
+ #
348
+ # Also, sometimes (like when porting older join table fixtures) you'll need
349
+ # to be able to get a hold of the identifier for a given label. ERB
350
+ # to the rescue:
351
+ #
352
+ # george_reginald:
353
+ # monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
354
+ # pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
355
+ #
356
+ # == Support for YAML defaults
357
+ #
358
+ # You probably already know how to use YAML to set and reuse defaults in
359
+ # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
360
+ #
361
+ # DEFAULTS: &DEFAULTS
362
+ # created_on: <%= 3.weeks.ago.to_s(:db) %>
363
+ #
364
+ # first:
365
+ # name: Smurf
366
+ # <<: *DEFAULTS
367
+ #
368
+ # second:
369
+ # name: Fraggle
370
+ # <<: *DEFAULTS
371
+ #
372
+ # Any fixture labeled "DEFAULTS" is safely ignored.
373
+ class FixtureSet
374
+ #--
375
+ # An instance of FixtureSet is normally stored in a single YAML file and possibly in a folder with the same name.
376
+ #++
377
+
378
+ MAX_ID = 2 ** 30 - 1
379
+
380
+ @@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
381
+
382
+ def self.find_table_name(fixture_set_name) # :nodoc:
383
+ ActiveSupport::Deprecation.warn(
384
+ "ActiveRecord::Fixtures.find_table_name is deprecated and shall be removed from future releases. Use ActiveRecord::Fixtures.default_fixture_model_name instead.")
385
+ default_fixture_model_name(fixture_set_name)
386
+ end
459
387
 
460
- def self.cache_for_connection(connection)
461
- @@all_cached_fixtures[connection.object_id] ||= {}
462
- @@all_cached_fixtures[connection.object_id]
463
- end
388
+ def self.default_fixture_model_name(fixture_set_name) # :nodoc:
389
+ ActiveRecord::Base.pluralize_table_names ?
390
+ fixture_set_name.singularize.camelize :
391
+ fixture_set_name.camelize
392
+ end
464
393
 
465
- def self.fixture_is_cached?(connection, table_name)
466
- cache_for_connection(connection)[table_name]
467
- end
394
+ def self.default_fixture_table_name(fixture_set_name) # :nodoc:
395
+ "#{ ActiveRecord::Base.table_name_prefix }"\
396
+ "#{ fixture_set_name.tr('/', '_') }"\
397
+ "#{ ActiveRecord::Base.table_name_suffix }".to_sym
398
+ end
468
399
 
469
- def self.cached_fixtures(connection, keys_to_fetch = nil)
470
- if keys_to_fetch
471
- fixtures = cache_for_connection(connection).values_at(*keys_to_fetch)
472
- else
473
- fixtures = cache_for_connection(connection).values
400
+ def self.reset_cache
401
+ @@all_cached_fixtures.clear
474
402
  end
475
- fixtures.size > 1 ? fixtures : fixtures.first
476
- end
477
403
 
478
- def self.cache_fixtures(connection, fixtures_map)
479
- cache_for_connection(connection).update(fixtures_map)
480
- end
404
+ def self.cache_for_connection(connection)
405
+ @@all_cached_fixtures[connection]
406
+ end
407
+
408
+ def self.fixture_is_cached?(connection, table_name)
409
+ cache_for_connection(connection)[table_name]
410
+ end
481
411
 
482
- def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
483
- object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
484
- if load_instances
485
- ActiveRecord::Base.silence do
486
- fixtures.each do |name, fixture|
412
+ def self.cached_fixtures(connection, keys_to_fetch = nil)
413
+ if keys_to_fetch
414
+ cache_for_connection(connection).values_at(*keys_to_fetch)
415
+ else
416
+ cache_for_connection(connection).values
417
+ end
418
+ end
419
+
420
+ def self.cache_fixtures(connection, fixtures_map)
421
+ cache_for_connection(connection).update(fixtures_map)
422
+ end
423
+
424
+ def self.instantiate_fixtures(object, fixture_set, load_instances = true)
425
+ if load_instances
426
+ fixture_set.each do |fixture_name, fixture|
487
427
  begin
488
- object.instance_variable_set "@#{name}", fixture.find
428
+ object.instance_variable_set "@#{fixture_name}", fixture.find
489
429
  rescue FixtureClassNotFound
490
430
  nil
491
431
  end
492
432
  end
493
433
  end
494
434
  end
495
- end
496
435
 
497
- def self.instantiate_all_loaded_fixtures(object, load_instances = true)
498
- all_loaded_fixtures.each do |table_name, fixtures|
499
- Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
436
+ def self.instantiate_all_loaded_fixtures(object, load_instances = true)
437
+ all_loaded_fixtures.each_value do |fixture_set|
438
+ instantiate_fixtures(object, fixture_set, load_instances)
439
+ end
500
440
  end
501
- end
502
441
 
503
- cattr_accessor :all_loaded_fixtures
504
- self.all_loaded_fixtures = {}
442
+ cattr_accessor :all_loaded_fixtures
443
+ self.all_loaded_fixtures = {}
505
444
 
506
- def self.create_fixtures(fixtures_directory, table_names, class_names = {})
507
- table_names = [table_names].flatten.map { |n| n.to_s }
508
- table_names.each { |n| class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/') }
509
- connection = block_given? ? yield : ActiveRecord::Base.connection
445
+ def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {})
446
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
447
+ class_names = class_names.stringify_keys
510
448
 
511
- table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
449
+ # FIXME: Apparently JK uses this.
450
+ connection = block_given? ? yield : ActiveRecord::Base.connection
512
451
 
513
- unless table_names_to_fetch.empty?
514
- ActiveRecord::Base.silence do
452
+ files_to_read = fixture_set_names.reject { |fs_name|
453
+ fixture_is_cached?(connection, fs_name)
454
+ }
455
+
456
+ unless files_to_read.empty?
515
457
  connection.disable_referential_integrity do
516
458
  fixtures_map = {}
517
459
 
518
- fixtures = table_names_to_fetch.map do |table_name|
519
- fixtures_map[table_name] = Fixtures.new(connection, table_name.tr('/', '_'), class_names[table_name.tr('/', '_').to_sym], File.join(fixtures_directory, table_name))
460
+ fixture_sets = files_to_read.map do |fs_name|
461
+ fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
462
+ connection,
463
+ fs_name,
464
+ class_names[fs_name] || default_fixture_model_name(fs_name),
465
+ ::File.join(fixtures_directory, fs_name))
520
466
  end
521
467
 
522
468
  all_loaded_fixtures.update(fixtures_map)
523
469
 
524
470
  connection.transaction(:requires_new => true) do
525
- fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
526
- fixtures.each { |fixture| fixture.insert_fixtures }
471
+ fixture_sets.each do |fs|
472
+ conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
473
+ table_rows = fs.table_rows
474
+
475
+ table_rows.keys.each do |table|
476
+ conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
477
+ end
478
+
479
+ table_rows.each do |fixture_set_name, rows|
480
+ rows.each do |row|
481
+ conn.insert_fixture(row, fixture_set_name)
482
+ end
483
+ end
484
+ end
527
485
 
528
486
  # Cap primary key sequences to max(pk).
529
487
  if connection.respond_to?(:reset_pk_sequence!)
530
- table_names.each do |table_name|
531
- connection.reset_pk_sequence!(table_name.tr('/', '_'))
488
+ fixture_sets.each do |fs|
489
+ connection.reset_pk_sequence!(fs.table_name)
532
490
  end
533
491
  end
534
492
  end
@@ -536,285 +494,212 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
536
494
  cache_fixtures(connection, fixtures_map)
537
495
  end
538
496
  end
497
+ cached_fixtures(connection, fixture_set_names)
539
498
  end
540
- cached_fixtures(connection, table_names)
541
- end
542
499
 
543
- # Returns a consistent, platform-independent identifier for +label+.
544
- # Identifiers are positive integers less than 2^32.
545
- def self.identify(label)
546
- Zlib.crc32(label.to_s) % MAX_ID
547
- end
500
+ # Returns a consistent, platform-independent identifier for +label+.
501
+ # Identifiers are positive integers less than 2^32.
502
+ def self.identify(label)
503
+ Zlib.crc32(label.to_s) % MAX_ID
504
+ end
548
505
 
549
- attr_reader :table_name, :name
550
-
551
- def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
552
- @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
553
- @name = table_name # preserve fixture base name
554
- @class_name = class_name ||
555
- (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
556
- @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
557
- @table_name = class_name.table_name if class_name.respond_to?(:table_name)
558
- @connection = class_name.connection if class_name.respond_to?(:connection)
559
- read_fixture_files
560
- end
506
+ attr_reader :table_name, :name, :fixtures, :model_class
561
507
 
562
- def delete_existing_fixtures
563
- @connection.delete "DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
564
- end
508
+ def initialize(connection, name, class_name, path)
509
+ @fixtures = {} # Ordered hash
510
+ @name = name
511
+ @path = path
512
+
513
+ if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
514
+ @model_class = class_name
515
+ else
516
+ @model_class = class_name.constantize rescue nil
517
+ end
518
+
519
+ @connection = ( model_class.respond_to?(:connection) ?
520
+ model_class.connection : connection )
521
+
522
+ @table_name = ( model_class.respond_to?(:table_name) ?
523
+ model_class.table_name :
524
+ self.class.default_fixture_table_name(name) )
565
525
 
566
- def insert_fixtures
567
- now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
568
- now = now.to_s(:db)
526
+ read_fixture_files
527
+ end
569
528
 
570
- # allow a standard key to be used for doing defaults in YAML
571
- if is_a?(Hash)
572
- delete('DEFAULTS')
573
- else
574
- delete(assoc('DEFAULTS'))
529
+ def [](x)
530
+ fixtures[x]
575
531
  end
576
532
 
577
- # track any join tables we need to insert later
578
- habtm_fixtures = Hash.new do |h, habtm|
579
- h[habtm] = HabtmFixtures.new(@connection, habtm.options[:join_table], nil, nil)
533
+ def []=(k,v)
534
+ fixtures[k] = v
580
535
  end
581
536
 
582
- each do |label, fixture|
583
- row = fixture.to_hash
537
+ def each(&block)
538
+ fixtures.each(&block)
539
+ end
584
540
 
585
- if model_class && model_class < ActiveRecord::Base
586
- # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
587
- if model_class.record_timestamps
588
- timestamp_column_names.each do |name|
589
- row[name] = now unless row.key?(name)
590
- end
591
- end
541
+ def size
542
+ fixtures.size
543
+ end
592
544
 
593
- # interpolate the fixture label
594
- row.each do |key, value|
595
- row[key] = label if value == "$LABEL"
596
- end
545
+ # Return a hash of rows to be inserted. The key is the table, the value is
546
+ # a list of rows to insert to that table.
547
+ def table_rows
548
+ now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
549
+ now = now.to_s(:db)
597
550
 
598
- # generate a primary key if necessary
599
- if has_primary_key_column? && !row.include?(primary_key_name)
600
- row[primary_key_name] = Fixtures.identify(label)
601
- end
551
+ # allow a standard key to be used for doing defaults in YAML
552
+ fixtures.delete('DEFAULTS')
553
+
554
+ # track any join tables we need to insert later
555
+ rows = Hash.new { |h,table| h[table] = [] }
556
+
557
+ rows[table_name] = fixtures.map do |label, fixture|
558
+ row = fixture.to_hash
602
559
 
603
- # If STI is used, find the correct subclass for association reflection
604
- reflection_class =
605
- if row.include?(inheritance_column_name)
606
- row[inheritance_column_name].constantize rescue model_class
607
- else
608
- model_class
560
+ if model_class && model_class < ActiveRecord::Base
561
+ # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
562
+ if model_class.record_timestamps
563
+ timestamp_column_names.each do |c_name|
564
+ row[c_name] = now unless row.key?(c_name)
565
+ end
609
566
  end
610
567
 
611
- reflection_class.reflect_on_all_associations.each do |association|
612
- case association.macro
613
- when :belongs_to
614
- # Do not replace association name with association foreign key if they are named the same
615
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
568
+ # interpolate the fixture label
569
+ row.each do |key, value|
570
+ row[key] = label if value == "$LABEL"
571
+ end
616
572
 
617
- if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
618
- if association.options[:polymorphic]
619
- if value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
620
- target_type = $1
621
- target_type_name = (association.options[:foreign_type] || "#{association.name}_type").to_s
573
+ # generate a primary key if necessary
574
+ if has_primary_key_column? && !row.include?(primary_key_name)
575
+ row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
576
+ end
577
+
578
+ # If STI is used, find the correct subclass for association reflection
579
+ reflection_class =
580
+ if row.include?(inheritance_column_name)
581
+ row[inheritance_column_name].constantize rescue model_class
582
+ else
583
+ model_class
584
+ end
622
585
 
586
+ reflection_class.reflect_on_all_associations.each do |association|
587
+ case association.macro
588
+ when :belongs_to
589
+ # Do not replace association name with association foreign key if they are named the same
590
+ fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
591
+
592
+ if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
593
+ if association.options[:polymorphic] && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
623
594
  # support polymorphic belongs_to as "label (Type)"
624
- row[target_type_name] = target_type
595
+ row[association.foreign_type] = $1
625
596
  end
626
- end
627
597
 
628
- row[fk_name] = Fixtures.identify(value)
629
- end
630
- when :has_and_belongs_to_many
631
- if (targets = row.delete(association.name.to_s))
632
- targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
633
- join_fixtures = habtm_fixtures[association]
634
-
635
- targets.each do |target|
636
- join_fixtures["#{label}_#{target}"] = Fixture.new(
637
- { association.primary_key_name => row[primary_key_name],
638
- association.association_foreign_key => Fixtures.identify(target) },
639
- nil, @connection)
598
+ row[fk_name] = ActiveRecord::FixtureSet.identify(value)
599
+ end
600
+ when :has_and_belongs_to_many
601
+ if (targets = row.delete(association.name.to_s))
602
+ targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
603
+ table_name = association.join_table
604
+ rows[table_name].concat targets.map { |target|
605
+ { association.foreign_key => row[primary_key_name],
606
+ association.association_foreign_key => ActiveRecord::FixtureSet.identify(target) }
607
+ }
640
608
  end
641
609
  end
642
610
  end
643
611
  end
644
- end
645
-
646
- @connection.insert_fixture(fixture, @table_name)
647
- end
648
-
649
- # insert any HABTM join tables we discovered
650
- habtm_fixtures.values.each do |fixture|
651
- fixture.delete_existing_fixtures
652
- fixture.insert_fixtures
653
- end
654
- end
655
-
656
- private
657
- class HabtmFixtures < ::Fixtures #:nodoc:
658
- def read_fixture_files; end
659
- end
660
612
 
661
- def model_class
662
- unless defined?(@model_class)
663
- @model_class =
664
- if @class_name.nil? || @class_name.is_a?(Class)
665
- @class_name
666
- else
667
- @class_name.constantize rescue nil
668
- end
613
+ row
669
614
  end
670
-
671
- @model_class
615
+ rows
672
616
  end
673
617
 
674
- def primary_key_name
675
- @primary_key_name ||= model_class && model_class.primary_key
676
- end
677
-
678
- def has_primary_key_column?
679
- @has_primary_key_column ||= primary_key_name &&
680
- model_class.columns.any? { |c| c.name == primary_key_name }
681
- end
682
-
683
- def timestamp_column_names
684
- @timestamp_column_names ||=
685
- %w(created_at created_on updated_at updated_on) & column_names
686
- end
618
+ private
619
+ def primary_key_name
620
+ @primary_key_name ||= model_class && model_class.primary_key
621
+ end
687
622
 
688
- def inheritance_column_name
689
- @inheritance_column_name ||= model_class && model_class.inheritance_column
690
- end
623
+ def has_primary_key_column?
624
+ @has_primary_key_column ||= primary_key_name &&
625
+ model_class.columns.any? { |c| c.name == primary_key_name }
626
+ end
691
627
 
692
- def column_names
693
- @column_names ||= @connection.columns(@table_name).collect { |c| c.name }
694
- end
628
+ def timestamp_column_names
629
+ @timestamp_column_names ||=
630
+ %w(created_at created_on updated_at updated_on) & column_names
631
+ end
695
632
 
696
- def read_fixture_files
697
- if File.file?(yaml_file_path)
698
- read_yaml_fixture_files
699
- elsif File.file?(csv_file_path)
700
- read_csv_fixture_files
701
- else
702
- raise FixturesFileNotFound, "Could not find #{yaml_file_path} or #{csv_file_path}"
633
+ def inheritance_column_name
634
+ @inheritance_column_name ||= model_class && model_class.inheritance_column
703
635
  end
704
- end
705
636
 
706
- def read_yaml_fixture_files
707
- yaml_string = ""
708
- Dir["#{@fixture_path}/**/*.yml"].select { |f| test(?f, f) }.each do |subfixture_path|
709
- yaml_string << IO.read(subfixture_path)
637
+ def column_names
638
+ @column_names ||= @connection.columns(@table_name).collect { |c| c.name }
710
639
  end
711
- yaml_string << IO.read(yaml_file_path)
712
-
713
- if yaml = parse_yaml_string(yaml_string)
714
- # If the file is an ordered map, extract its children.
715
- yaml_value =
716
- if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
717
- yaml.value
718
- else
719
- [yaml]
720
- end
721
640
 
722
- yaml_value.each do |fixture|
723
- raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{fixture}" unless fixture.respond_to?(:each)
724
- fixture.each do |name, data|
725
- unless data
726
- raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
727
- end
641
+ def read_fixture_files
642
+ yaml_files = Dir["#{@path}/**/*.yml"].select { |f|
643
+ ::File.file?(f)
644
+ } + [yaml_file_path]
728
645
 
729
- self[name] = Fixture.new(data, model_class, @connection)
646
+ yaml_files.each do |file|
647
+ FixtureSet::File.open(file) do |fh|
648
+ fh.each do |fixture_name, row|
649
+ fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
650
+ end
730
651
  end
731
652
  end
732
653
  end
733
- end
734
654
 
735
- def read_csv_fixture_files
736
- reader = CSV.parse(erb_render(IO.read(csv_file_path)))
737
- header = reader.shift
738
- i = 0
739
- reader.each do |row|
740
- data = {}
741
- row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
742
- self["#{@class_name.to_s.underscore}_#{i+=1}"] = Fixture.new(data, model_class, @connection)
655
+ def yaml_file_path
656
+ "#{@path}.yml"
743
657
  end
744
- end
745
658
 
746
- def yaml_file_path
747
- "#{@fixture_path}.yml"
748
- end
659
+ end
749
660
 
750
- def csv_file_path
751
- @fixture_path + ".csv"
752
- end
661
+ #--
662
+ # Deprecate 'Fixtures' in favor of 'FixtureSet'.
663
+ #++
664
+ # :nodoc:
665
+ Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
753
666
 
754
- def yaml_fixtures_key(path)
755
- File.basename(@fixture_path).split(".").first
756
- end
667
+ class Fixture #:nodoc:
668
+ include Enumerable
757
669
 
758
- def parse_yaml_string(fixture_content)
759
- YAML::load(erb_render(fixture_content))
760
- rescue => error
761
- raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}"
670
+ class FixtureError < StandardError #:nodoc:
762
671
  end
763
672
 
764
- def erb_render(fixture_content)
765
- ERB.new(fixture_content).result
673
+ class FormatError < FixtureError #:nodoc:
766
674
  end
767
- end
768
675
 
769
- class Fixture #:nodoc:
770
- include Enumerable
771
-
772
- class FixtureError < StandardError #:nodoc:
773
- end
676
+ attr_reader :model_class, :fixture
774
677
 
775
- class FormatError < FixtureError #:nodoc:
776
- end
777
-
778
- attr_reader :model_class
779
-
780
- def initialize(fixture, model_class, connection = ActiveRecord::Base.connection)
781
- @connection = connection
782
- @fixture = fixture
783
- @model_class = model_class.is_a?(Class) ? model_class : model_class.constantize rescue nil
784
- end
785
-
786
- def class_name
787
- @model_class.name if @model_class
788
- end
789
-
790
- def each
791
- @fixture.each { |item| yield item }
792
- end
678
+ def initialize(fixture, model_class)
679
+ @fixture = fixture
680
+ @model_class = model_class
681
+ end
793
682
 
794
- def [](key)
795
- @fixture[key]
796
- end
683
+ def class_name
684
+ model_class.name if model_class
685
+ end
797
686
 
798
- def to_hash
799
- @fixture
800
- end
687
+ def each
688
+ fixture.each { |item| yield item }
689
+ end
801
690
 
802
- def key_list
803
- @fixture.keys.map { |column_name| @connection.quote_column_name(column_name) }.join(', ')
804
- end
691
+ def [](key)
692
+ fixture[key]
693
+ end
805
694
 
806
- def value_list
807
- cols = (model_class && model_class < ActiveRecord::Base) ? model_class.columns_hash : {}
808
- @fixture.map do |key, value|
809
- @connection.quote(value, cols[key]).gsub('[^\]\\n', "\n").gsub('[^\]\\r', "\r")
810
- end.join(', ')
811
- end
695
+ alias :to_hash :fixture
812
696
 
813
- def find
814
- if model_class
815
- model_class.find(self[model_class.primary_key])
816
- else
817
- raise FixtureClassNotFound, "No class attached to find."
697
+ def find
698
+ if model_class
699
+ model_class.find(fixture[model_class.primary_key])
700
+ else
701
+ raise FixtureClassNotFound, "No class attached to find."
702
+ end
818
703
  end
819
704
  end
820
705
  end
@@ -823,48 +708,71 @@ module ActiveRecord
823
708
  module TestFixtures
824
709
  extend ActiveSupport::Concern
825
710
 
826
- included do
827
- setup :setup_fixtures
828
- teardown :teardown_fixtures
711
+ def before_setup
712
+ setup_fixtures
713
+ super
714
+ end
715
+
716
+ def after_teardown
717
+ super
718
+ teardown_fixtures
719
+ end
829
720
 
830
- superclass_delegating_accessor :fixture_path
831
- superclass_delegating_accessor :fixture_table_names
832
- superclass_delegating_accessor :fixture_class_names
833
- superclass_delegating_accessor :use_transactional_fixtures
834
- superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
835
- superclass_delegating_accessor :pre_loaded_fixtures
721
+ included do
722
+ class_attribute :fixture_path, :instance_writer => false
723
+ class_attribute :fixture_table_names
724
+ class_attribute :fixture_class_names
725
+ class_attribute :use_transactional_fixtures
726
+ class_attribute :use_instantiated_fixtures # true, false, or :no_instances
727
+ class_attribute :pre_loaded_fixtures
836
728
 
837
729
  self.fixture_table_names = []
838
730
  self.use_transactional_fixtures = true
839
731
  self.use_instantiated_fixtures = false
840
732
  self.pre_loaded_fixtures = false
841
733
 
842
- self.fixture_class_names = {}
734
+ self.fixture_class_names = Hash.new do |h, fixture_set_name|
735
+ h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name)
736
+ end
843
737
  end
844
738
 
845
739
  module ClassMethods
740
+ # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
741
+ #
742
+ # Examples:
743
+ #
744
+ # set_fixture_class some_fixture: SomeModel,
745
+ # 'namespaced/fixture' => Another::Model
746
+ #
747
+ # The keys must be the fixture names, that coincide with the short paths to the fixture files.
748
+ #--
749
+ # It is also possible to pass the class name instead of the class:
750
+ # set_fixture_class 'some_fixture' => 'SomeModel'
751
+ # I think this option is redundant, i propose to deprecate it.
752
+ # Isn't it easier to always pass the class itself?
753
+ # (2011-12-20 alexeymuranov)
754
+ #++
846
755
  def set_fixture_class(class_names = {})
847
- self.fixture_class_names = self.fixture_class_names.merge(class_names)
756
+ self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
848
757
  end
849
758
 
850
- def fixtures(*table_names)
851
- if table_names.first == :all
852
- table_names = Dir["#{fixture_path}/**/*.{yml,csv}"]
853
- table_names.map! { |f| f[(fixture_path.size + 1)..-5] }
759
+ def fixtures(*fixture_set_names)
760
+ if fixture_set_names.first == :all
761
+ fixture_set_names = Dir["#{fixture_path}/**/*.{yml}"]
762
+ fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
854
763
  else
855
- table_names = table_names.flatten.map { |n| n.to_s }
764
+ fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
856
765
  end
857
766
 
858
- self.fixture_table_names |= table_names
859
- require_fixture_classes(table_names)
860
- setup_fixture_accessors(table_names)
767
+ self.fixture_table_names |= fixture_set_names
768
+ require_fixture_classes(fixture_set_names)
769
+ setup_fixture_accessors(fixture_set_names)
861
770
  end
862
771
 
863
772
  def try_to_load_dependency(file_name)
864
773
  require_dependency file_name
865
774
  rescue LoadError => e
866
- # Let's hope the developer has included it himself
867
-
775
+ # Let's hope the developer has included it
868
776
  # Let's warn in case this is a subdependency, otherwise
869
777
  # subdependency error messages are totally cryptic
870
778
  if ActiveRecord::Base.logger
@@ -872,38 +780,48 @@ module ActiveRecord
872
780
  end
873
781
  end
874
782
 
875
- def require_fixture_classes(table_names = nil)
876
- (table_names || fixture_table_names).each do |table_name|
877
- file_name = table_name.to_s
783
+ def require_fixture_classes(fixture_set_names = nil)
784
+ if fixture_set_names
785
+ fixture_set_names = fixture_set_names.map { |n| n.to_s }
786
+ else
787
+ fixture_set_names = fixture_table_names
788
+ end
789
+
790
+ fixture_set_names.each do |file_name|
878
791
  file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
879
792
  try_to_load_dependency(file_name)
880
793
  end
881
794
  end
882
795
 
883
- def setup_fixture_accessors(table_names = nil)
884
- table_names = Array.wrap(table_names || fixture_table_names)
885
- table_names.each do |table_name|
886
- table_name = table_name.to_s.tr('./', '_')
796
+ def setup_fixture_accessors(fixture_set_names = nil)
797
+ fixture_set_names = Array(fixture_set_names || fixture_table_names)
798
+ methods = Module.new do
799
+ fixture_set_names.each do |fs_name|
800
+ fs_name = fs_name.to_s
801
+ accessor_name = fs_name.tr('/', '_').to_sym
887
802
 
888
- redefine_method(table_name) do |*fixtures|
889
- force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
803
+ define_method(accessor_name) do |*fixture_names|
804
+ force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
890
805
 
891
- @fixture_cache[table_name] ||= {}
806
+ @fixture_cache[fs_name] ||= {}
892
807
 
893
- instances = fixtures.map do |fixture|
894
- @fixture_cache[table_name].delete(fixture) if force_reload
808
+ instances = fixture_names.map do |f_name|
809
+ f_name = f_name.to_s
810
+ @fixture_cache[fs_name].delete(f_name) if force_reload
895
811
 
896
- if @loaded_fixtures[table_name][fixture.to_s]
897
- @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
898
- else
899
- raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
812
+ if @loaded_fixtures[fs_name][f_name]
813
+ @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
814
+ else
815
+ raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
816
+ end
900
817
  end
901
- end
902
818
 
903
- instances.size == 1 ? instances.first : instances
819
+ instances.size == 1 ? instances.first : instances
820
+ end
821
+ private accessor_name
904
822
  end
905
- private table_name
906
823
  end
824
+ include methods
907
825
  end
908
826
 
909
827
  def uses_transaction(*methods)
@@ -923,13 +841,14 @@ module ActiveRecord
923
841
  end
924
842
 
925
843
  def setup_fixtures
926
- return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
844
+ return if ActiveRecord::Base.configurations.blank?
927
845
 
928
846
  if pre_loaded_fixtures && !use_transactional_fixtures
929
847
  raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
930
848
  end
931
849
 
932
850
  @fixture_cache = {}
851
+ @fixture_connections = []
933
852
  @@already_loaded_fixtures ||= {}
934
853
 
935
854
  # Load fixtures once and begin transaction.
@@ -937,17 +856,18 @@ module ActiveRecord
937
856
  if @@already_loaded_fixtures[self.class]
938
857
  @loaded_fixtures = @@already_loaded_fixtures[self.class]
939
858
  else
940
- load_fixtures
859
+ @loaded_fixtures = load_fixtures
941
860
  @@already_loaded_fixtures[self.class] = @loaded_fixtures
942
861
  end
943
- ActiveRecord::Base.connection.increment_open_transactions
944
- ActiveRecord::Base.connection.transaction_joinable = false
945
- ActiveRecord::Base.connection.begin_db_transaction
862
+ @fixture_connections = enlist_fixture_connections
863
+ @fixture_connections.each do |connection|
864
+ connection.begin_transaction joinable: false
865
+ end
946
866
  # Load fixtures for every test.
947
867
  else
948
- Fixtures.reset_cache
868
+ ActiveRecord::FixtureSet.reset_cache
949
869
  @@already_loaded_fixtures[self.class] = nil
950
- load_fixtures
870
+ @loaded_fixtures = load_fixtures
951
871
  end
952
872
 
953
873
  # Instantiate fixtures for every test if requested.
@@ -955,31 +875,29 @@ module ActiveRecord
955
875
  end
956
876
 
957
877
  def teardown_fixtures
958
- return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
959
-
960
- unless run_in_transaction?
961
- Fixtures.reset_cache
962
- end
878
+ return if ActiveRecord::Base.configurations.blank?
963
879
 
964
880
  # Rollback changes if a transaction is active.
965
- if run_in_transaction? && ActiveRecord::Base.connection.open_transactions != 0
966
- ActiveRecord::Base.connection.rollback_db_transaction
967
- ActiveRecord::Base.connection.decrement_open_transactions
881
+ if run_in_transaction?
882
+ @fixture_connections.each do |connection|
883
+ connection.rollback_transaction if connection.transaction_open?
884
+ end
885
+ @fixture_connections.clear
886
+ else
887
+ ActiveRecord::FixtureSet.reset_cache
968
888
  end
889
+
969
890
  ActiveRecord::Base.clear_active_connections!
970
891
  end
971
892
 
893
+ def enlist_fixture_connections
894
+ ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
895
+ end
896
+
972
897
  private
973
898
  def load_fixtures
974
- @loaded_fixtures = {}
975
- fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
976
- unless fixtures.nil?
977
- if fixtures.instance_of?(Fixtures)
978
- @loaded_fixtures[fixtures.name] = fixtures
979
- else
980
- fixtures.each { |f| @loaded_fixtures[f.name] = f }
981
- end
982
- end
899
+ fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
900
+ Hash[fixtures.map { |f| [f.name, f] }]
983
901
  end
984
902
 
985
903
  # for pre_loaded_fixtures, only require the classes once. huge speed improvement
@@ -987,16 +905,16 @@ module ActiveRecord
987
905
 
988
906
  def instantiate_fixtures
989
907
  if pre_loaded_fixtures
990
- raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
908
+ raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
991
909
  unless @@required_fixture_classes
992
- self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
910
+ self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys
993
911
  @@required_fixture_classes = true
994
912
  end
995
- Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
913
+ ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
996
914
  else
997
915
  raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
998
- @loaded_fixtures.each do |table_name, fixtures|
999
- Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
916
+ @loaded_fixtures.each_value do |fixture_set|
917
+ ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
1000
918
  end
1001
919
  end
1002
920
  end