activerecord 3.1.10 → 4.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

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