activerecord 3.2.19 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

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