activerecord 2.3.18 → 3.2.22

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