activerecord 4.2.11.2 → 6.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 (372) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +613 -1638
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +13 -12
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record.rb +41 -22
  8. data/lib/active_record/aggregations.rb +267 -251
  9. data/lib/active_record/association_relation.rb +11 -6
  10. data/lib/active_record/associations.rb +1737 -1597
  11. data/lib/active_record/associations/alias_tracker.rb +29 -35
  12. data/lib/active_record/associations/association.rb +125 -58
  13. data/lib/active_record/associations/association_scope.rb +103 -132
  14. data/lib/active_record/associations/belongs_to_association.rb +65 -60
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -40
  17. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  18. data/lib/active_record/associations/builder/collection_association.rb +10 -33
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
  20. data/lib/active_record/associations/builder/has_many.rb +8 -4
  21. data/lib/active_record/associations/builder/has_one.rb +46 -5
  22. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  23. data/lib/active_record/associations/collection_association.rb +131 -287
  24. data/lib/active_record/associations/collection_proxy.rb +241 -146
  25. data/lib/active_record/associations/foreign_association.rb +10 -1
  26. data/lib/active_record/associations/has_many_association.rb +34 -97
  27. data/lib/active_record/associations/has_many_through_association.rb +60 -87
  28. data/lib/active_record/associations/has_one_association.rb +61 -49
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +137 -167
  31. data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +90 -92
  35. data/lib/active_record/associations/preloader/association.rb +90 -123
  36. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  37. data/lib/active_record/associations/singular_association.rb +18 -39
  38. data/lib/active_record/associations/through_association.rb +38 -18
  39. data/lib/active_record/attribute_assignment.rb +56 -183
  40. data/lib/active_record/attribute_decorators.rb +39 -15
  41. data/lib/active_record/attribute_methods.rb +120 -135
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
  43. data/lib/active_record/attribute_methods/dirty.rb +174 -144
  44. data/lib/active_record/attribute_methods/primary_key.rb +91 -83
  45. data/lib/active_record/attribute_methods/query.rb +6 -5
  46. data/lib/active_record/attribute_methods/read.rb +20 -76
  47. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
  49. data/lib/active_record/attribute_methods/write.rb +32 -54
  50. data/lib/active_record/attributes.rb +214 -82
  51. data/lib/active_record/autosave_association.rb +91 -37
  52. data/lib/active_record/base.rb +57 -45
  53. data/lib/active_record/callbacks.rb +100 -74
  54. data/lib/active_record/coders/json.rb +3 -1
  55. data/lib/active_record/coders/yaml_column.rb +24 -12
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
  69. data/lib/active_record/connection_adapters/column.rb +56 -43
  70. data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
  117. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -345
  127. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  128. data/lib/active_record/connection_handling.rb +176 -41
  129. data/lib/active_record/core.rb +251 -231
  130. data/lib/active_record/counter_cache.rb +67 -49
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +87 -105
  137. data/lib/active_record/enum.rb +163 -86
  138. data/lib/active_record/errors.rb +188 -53
  139. data/lib/active_record/explain.rb +23 -11
  140. data/lib/active_record/explain_registry.rb +4 -2
  141. data/lib/active_record/explain_subscriber.rb +10 -5
  142. data/lib/active_record/fixture_set/file.rb +35 -9
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +228 -499
  148. data/lib/active_record/gem_version.rb +6 -4
  149. data/lib/active_record/inheritance.rb +158 -112
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +123 -29
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +21 -3
  154. data/lib/active_record/locale/en.yml +3 -2
  155. data/lib/active_record/locking/optimistic.rb +87 -96
  156. data/lib/active_record/locking/pessimistic.rb +18 -6
  157. data/lib/active_record/log_subscriber.rb +76 -33
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +621 -303
  162. data/lib/active_record/migration/command_recorder.rb +177 -90
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +8 -6
  165. data/lib/active_record/model_schema.rb +312 -112
  166. data/lib/active_record/nested_attributes.rb +264 -222
  167. data/lib/active_record/no_touching.rb +14 -1
  168. data/lib/active_record/null_relation.rb +24 -37
  169. data/lib/active_record/persistence.rb +557 -125
  170. data/lib/active_record/query_cache.rb +19 -23
  171. data/lib/active_record/querying.rb +43 -29
  172. data/lib/active_record/railtie.rb +143 -44
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +2 -0
  175. data/lib/active_record/railties/controller_runtime.rb +34 -33
  176. data/lib/active_record/railties/databases.rake +328 -185
  177. data/lib/active_record/readonly_attributes.rb +5 -4
  178. data/lib/active_record/reflection.rb +428 -279
  179. data/lib/active_record/relation.rb +518 -341
  180. data/lib/active_record/relation/batches.rb +207 -55
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +267 -253
  183. data/lib/active_record/relation/delegation.rb +70 -80
  184. data/lib/active_record/relation/finder_methods.rb +277 -241
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +78 -87
  187. data/lib/active_record/relation/predicate_builder.rb +114 -119
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +575 -394
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +11 -13
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +79 -42
  202. data/lib/active_record/runtime_registry.rb +6 -4
  203. data/lib/active_record/sanitization.rb +144 -121
  204. data/lib/active_record/schema.rb +21 -24
  205. data/lib/active_record/schema_dumper.rb +112 -93
  206. data/lib/active_record/schema_migration.rb +24 -17
  207. data/lib/active_record/scoping.rb +45 -26
  208. data/lib/active_record/scoping/default.rb +101 -85
  209. data/lib/active_record/scoping/named.rb +86 -33
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +5 -5
  212. data/lib/active_record/statement_cache.rb +73 -36
  213. data/lib/active_record/store.rb +127 -42
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +307 -100
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +86 -40
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +216 -150
  225. data/lib/active_record/translation.rb +3 -1
  226. data/lib/active_record/type.rb +78 -23
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +4 -45
  229. data/lib/active_record/type/date_time.rb +4 -49
  230. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  231. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +24 -15
  235. data/lib/active_record/type/text.rb +2 -2
  236. data/lib/active_record/type/time.rb +11 -16
  237. data/lib/active_record/type/type_map.rb +15 -17
  238. data/lib/active_record/type/unsigned_integer.rb +9 -7
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +39 -35
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +13 -4
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +14 -13
  247. data/lib/active_record/validations/uniqueness.rb +42 -55
  248. data/lib/active_record/version.rb +3 -1
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +7 -5
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +31 -1
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
  337. data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  340. metadata +164 -59
  341. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  342. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  343. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  344. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  345. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  346. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  347. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  348. data/lib/active_record/attribute.rb +0 -163
  349. data/lib/active_record/attribute_set.rb +0 -81
  350. data/lib/active_record/attribute_set/builder.rb +0 -106
  351. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  352. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  353. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  354. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  355. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  356. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  359. data/lib/active_record/type/big_integer.rb +0 -13
  360. data/lib/active_record/type/binary.rb +0 -50
  361. data/lib/active_record/type/boolean.rb +0 -31
  362. data/lib/active_record/type/decimal.rb +0 -64
  363. data/lib/active_record/type/decorator.rb +0 -14
  364. data/lib/active_record/type/float.rb +0 -19
  365. data/lib/active_record/type/integer.rb +0 -59
  366. data/lib/active_record/type/mutable.rb +0 -16
  367. data/lib/active_record/type/numeric.rb +0 -36
  368. data/lib/active_record/type/string.rb +0 -40
  369. data/lib/active_record/type/time_value.rb +0 -38
  370. data/lib/active_record/type/value.rb +0 -110
  371. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
  372. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,5 +1,7 @@
1
- require 'erb'
2
- require 'yaml'
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "yaml"
3
5
 
4
6
  module ActiveRecord
5
7
  class FixtureSet
@@ -17,38 +19,62 @@ module ActiveRecord
17
19
 
18
20
  def initialize(file)
19
21
  @file = file
20
- @rows = nil
21
22
  end
22
23
 
23
24
  def each(&block)
24
25
  rows.each(&block)
25
26
  end
26
27
 
28
+ def model_class
29
+ config_row["model_class"]
30
+ end
27
31
 
28
32
  private
29
33
  def rows
30
- return @rows if @rows
34
+ @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
35
+ end
31
36
 
32
- begin
37
+ def config_row
38
+ @config_row ||= begin
39
+ row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
40
+ if row
41
+ row.last
42
+ else
43
+ { 'model_class': nil }
44
+ end
45
+ end
46
+ end
47
+
48
+ def raw_rows
49
+ @raw_rows ||= begin
33
50
  data = YAML.load(render(IO.read(@file)))
51
+ data ? validate(data).to_a : []
34
52
  rescue ArgumentError, Psych::SyntaxError => error
35
53
  raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
36
54
  end
37
- @rows = data ? validate(data).to_a : []
55
+ end
56
+
57
+ def prepare_erb(content)
58
+ erb = ERB.new(content)
59
+ erb.filename = @file
60
+ erb
38
61
  end
39
62
 
40
63
  def render(content)
41
64
  context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
42
- ERB.new(content).result(context.get_binding)
65
+ prepare_erb(content).result(context.get_binding)
43
66
  end
44
67
 
45
68
  # Validate our unmarshalled data.
46
69
  def validate(data)
47
70
  unless Hash === data || YAML::Omap === data
48
- raise Fixture::FormatError, 'fixture is not a hash'
71
+ raise Fixture::FormatError, "fixture is not a hash: #{@file}"
49
72
  end
50
73
 
51
- raise Fixture::FormatError unless data.all? { |name, row| Hash === row }
74
+ invalid = data.reject { |_, row| Hash === row }
75
+ if invalid.any?
76
+ raise Fixture::FormatError, "fixture key is not a hash: #{@file}, keys: #{invalid.keys.inspect}"
77
+ end
52
78
  data
53
79
  end
54
80
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class FixtureSet
5
+ class ModelMetadata # :nodoc:
6
+ def initialize(model_class)
7
+ @model_class = model_class
8
+ end
9
+
10
+ def primary_key_name
11
+ @primary_key_name ||= @model_class && @model_class.primary_key
12
+ end
13
+
14
+ def primary_key_type
15
+ @primary_key_type ||= @model_class && @model_class.type_for_attribute(@model_class.primary_key).type
16
+ end
17
+
18
+ def has_primary_key_column?
19
+ @has_primary_key_column ||= primary_key_name &&
20
+ @model_class.columns.any? { |col| col.name == primary_key_name }
21
+ end
22
+
23
+ def timestamp_column_names
24
+ @timestamp_column_names ||=
25
+ %w(created_at created_on updated_at updated_on) & @model_class.column_names
26
+ end
27
+
28
+ def inheritance_column_name
29
+ @inheritance_column_name ||= @model_class && @model_class.inheritance_column
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE: This class has to be defined in compact style in
4
+ # order for rendering context subclassing to work correctly.
5
+ class ActiveRecord::FixtureSet::RenderContext # :nodoc:
6
+ def self.create_subclass
7
+ Class.new(ActiveRecord::FixtureSet.context_class) do
8
+ def get_binding
9
+ binding()
10
+ end
11
+
12
+ def binary(path)
13
+ %(!!binary "#{Base64.strict_encode64(File.read(path))}")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class FixtureSet
5
+ class TableRow # :nodoc:
6
+ class ReflectionProxy # :nodoc:
7
+ def initialize(association)
8
+ @association = association
9
+ end
10
+
11
+ def join_table
12
+ @association.join_table
13
+ end
14
+
15
+ def name
16
+ @association.name
17
+ end
18
+
19
+ def primary_key_type
20
+ @association.klass.type_for_attribute(@association.klass.primary_key).type
21
+ end
22
+ end
23
+
24
+ class HasManyThroughProxy < ReflectionProxy # :nodoc:
25
+ def rhs_key
26
+ @association.foreign_key
27
+ end
28
+
29
+ def lhs_key
30
+ @association.through_reflection.foreign_key
31
+ end
32
+
33
+ def join_table
34
+ @association.through_reflection.table_name
35
+ end
36
+ end
37
+
38
+ def initialize(fixture, table_rows:, label:, now:)
39
+ @table_rows = table_rows
40
+ @label = label
41
+ @now = now
42
+ @row = fixture.to_hash
43
+ fill_row_model_attributes
44
+ end
45
+
46
+ def to_hash
47
+ @row
48
+ end
49
+
50
+ private
51
+
52
+ def model_metadata
53
+ @table_rows.model_metadata
54
+ end
55
+
56
+ def model_class
57
+ @table_rows.model_class
58
+ end
59
+
60
+ def fill_row_model_attributes
61
+ return unless model_class
62
+ fill_timestamps
63
+ interpolate_label
64
+ generate_primary_key
65
+ resolve_enums
66
+ resolve_sti_reflections
67
+ end
68
+
69
+ def reflection_class
70
+ @reflection_class ||= if @row.include?(model_metadata.inheritance_column_name)
71
+ @row[model_metadata.inheritance_column_name].constantize rescue model_class
72
+ else
73
+ model_class
74
+ end
75
+ end
76
+
77
+ def fill_timestamps
78
+ # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
79
+ if model_class.record_timestamps
80
+ model_metadata.timestamp_column_names.each do |c_name|
81
+ @row[c_name] = @now unless @row.key?(c_name)
82
+ end
83
+ end
84
+ end
85
+
86
+ def interpolate_label
87
+ # interpolate the fixture label
88
+ @row.each do |key, value|
89
+ @row[key] = value.gsub("$LABEL", @label.to_s) if value.is_a?(String)
90
+ end
91
+ end
92
+
93
+ def generate_primary_key
94
+ # generate a primary key if necessary
95
+ if model_metadata.has_primary_key_column? && !@row.include?(model_metadata.primary_key_name)
96
+ @row[model_metadata.primary_key_name] = ActiveRecord::FixtureSet.identify(
97
+ @label, model_metadata.primary_key_type
98
+ )
99
+ end
100
+ end
101
+
102
+ def resolve_enums
103
+ model_class.defined_enums.each do |name, values|
104
+ if @row.include?(name)
105
+ @row[name] = values.fetch(@row[name], @row[name])
106
+ end
107
+ end
108
+ end
109
+
110
+ def resolve_sti_reflections
111
+ # If STI is used, find the correct subclass for association reflection
112
+ reflection_class._reflections.each_value do |association|
113
+ case association.macro
114
+ when :belongs_to
115
+ # Do not replace association name with association foreign key if they are named the same
116
+ fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
117
+
118
+ if association.name.to_s != fk_name && value = @row.delete(association.name.to_s)
119
+ if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
120
+ # support polymorphic belongs_to as "label (Type)"
121
+ @row[association.foreign_type] = $1
122
+ end
123
+
124
+ fk_type = reflection_class.type_for_attribute(fk_name).type
125
+ @row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
126
+ end
127
+ when :has_many
128
+ if association.options[:through]
129
+ add_join_records(HasManyThroughProxy.new(association))
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def add_join_records(association)
136
+ # This is the case when the join table has no fixtures file
137
+ if (targets = @row.delete(association.name.to_s))
138
+ table_name = association.join_table
139
+ column_type = association.primary_key_type
140
+ lhs_key = association.lhs_key
141
+ rhs_key = association.rhs_key
142
+
143
+ targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
144
+ joins = targets.map do |target|
145
+ { lhs_key => @row[model_metadata.primary_key_name],
146
+ rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
147
+ end
148
+ @table_rows.tables[table_name].concat(joins)
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/fixture_set/table_row"
4
+ require "active_record/fixture_set/model_metadata"
5
+
6
+ module ActiveRecord
7
+ class FixtureSet
8
+ class TableRows # :nodoc:
9
+ def initialize(table_name, model_class:, fixtures:, config:)
10
+ @model_class = model_class
11
+
12
+ # track any join tables we need to insert later
13
+ @tables = Hash.new { |h, table| h[table] = [] }
14
+
15
+ # ensure this table is loaded before any HABTM associations
16
+ @tables[table_name] = nil
17
+
18
+ build_table_rows_from(table_name, fixtures, config)
19
+ end
20
+
21
+ attr_reader :tables, :model_class
22
+
23
+ def to_hash
24
+ @tables.transform_values { |rows| rows.map(&:to_hash) }
25
+ end
26
+
27
+ def model_metadata
28
+ @model_metadata ||= ModelMetadata.new(model_class)
29
+ end
30
+
31
+ private
32
+
33
+ def build_table_rows_from(table_name, fixtures, config)
34
+ now = config.default_timezone == :utc ? Time.now.utc : Time.now
35
+
36
+ @tables[table_name] = fixtures.map do |label, fixture|
37
+ TableRow.new(
38
+ fixture,
39
+ table_rows: self,
40
+ label: label,
41
+ now: now,
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,10 +1,16 @@
1
- require 'erb'
2
- require 'yaml'
3
- require 'zlib'
4
- require 'active_support/dependencies'
5
- require 'active_support/core_ext/digest/uuid'
6
- require 'active_record/fixture_set/file'
7
- require 'active_record/errors'
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "yaml"
5
+ require "zlib"
6
+ require "set"
7
+ require "active_support/dependencies"
8
+ require "active_support/core_ext/digest/uuid"
9
+ require "active_record/fixture_set/file"
10
+ require "active_record/fixture_set/render_context"
11
+ require "active_record/fixture_set/table_rows"
12
+ require "active_record/test_fixtures"
13
+ require "active_record/errors"
8
14
 
9
15
  module ActiveRecord
10
16
  class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
@@ -65,17 +71,36 @@ module ActiveRecord
65
71
  # By default, +test_helper.rb+ will load all of your fixtures into your test
66
72
  # database, so this test will succeed.
67
73
  #
68
- # The testing environment will automatically load the all fixtures into the database before each
74
+ # The testing environment will automatically load all the fixtures into the database before each
69
75
  # test. To ensure consistent data, the environment deletes the fixtures before running the load.
70
76
  #
71
77
  # In addition to being available in the database, the fixture's data may also be accessed by
72
- # using a special dynamic method, which has the same name as the model, and accepts the
73
- # name of the fixture to instantiate:
78
+ # using a special dynamic method, which has the same name as the model.
74
79
  #
75
- # test "find" do
80
+ # Passing in a fixture name to this dynamic method returns the fixture matching this name:
81
+ #
82
+ # test "find one" do
76
83
  # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
77
84
  # end
78
85
  #
86
+ # Passing in multiple fixture names returns all fixtures matching these names:
87
+ #
88
+ # test "find all by name" do
89
+ # assert_equal 2, web_sites(:rubyonrails, :google).length
90
+ # end
91
+ #
92
+ # Passing in no arguments returns all fixtures:
93
+ #
94
+ # test "find all" do
95
+ # assert_equal 2, web_sites.length
96
+ # end
97
+ #
98
+ # Passing in any fixture name that does not exist will raise <tt>StandardError</tt>:
99
+ #
100
+ # test "find by name that does not exist" do
101
+ # assert_raise(StandardError) { web_sites(:reddit) }
102
+ # end
103
+ #
79
104
  # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
80
105
  # following tests:
81
106
  #
@@ -87,8 +112,8 @@ module ActiveRecord
87
112
  # assert_equal "Ruby on Rails", @rubyonrails.name
88
113
  # end
89
114
  #
90
- # In order to use these methods to access fixtured data within your testcases, you must specify one of the
91
- # following in your <tt>ActiveSupport::TestCase</tt>-derived class:
115
+ # In order to use these methods to access fixtured data within your test cases, you must specify one of the
116
+ # following in your ActiveSupport::TestCase-derived class:
92
117
  #
93
118
  # - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
94
119
  # self.use_instantiated_fixtures = true
@@ -102,14 +127,14 @@ module ActiveRecord
102
127
  #
103
128
  # = Dynamic fixtures with ERB
104
129
  #
105
- # Some times you don't care about the content of the fixtures as much as you care about the volume.
130
+ # Sometimes you don't care about the content of the fixtures as much as you care about the volume.
106
131
  # In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
107
132
  # testing, like:
108
133
  #
109
134
  # <% 1.upto(1000) do |i| %>
110
135
  # fix_<%= i %>:
111
136
  # id: <%= i %>
112
- # name: guy_<%= 1 %>
137
+ # name: guy_<%= i %>
113
138
  # <% end %>
114
139
  #
115
140
  # This will create 1000 very simple fixtures.
@@ -123,49 +148,49 @@ module ActiveRecord
123
148
  #
124
149
  # Helper methods defined in a fixture will not be available in other fixtures, to prevent against
125
150
  # unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
126
- # that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>.
151
+ # that is included in ActiveRecord::FixtureSet.context_class.
127
152
  #
128
- # - define a helper method in `test_helper.rb`
153
+ # - define a helper method in <tt>test_helper.rb</tt>
129
154
  # module FixtureFileHelpers
130
155
  # def file_sha(path)
131
156
  # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
132
157
  # end
133
158
  # end
134
- # ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
159
+ # ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
135
160
  #
136
161
  # - use the helper method in a fixture
137
162
  # photo:
138
163
  # name: kitten.png
139
164
  # sha: <%= file_sha 'files/kitten.png' %>
140
165
  #
141
- # = Transactional Fixtures
166
+ # = Transactional Tests
142
167
  #
143
168
  # Test cases can use begin+rollback to isolate their changes to the database instead of having to
144
169
  # delete+insert for every test case.
145
170
  #
146
171
  # class FooTest < ActiveSupport::TestCase
147
- # self.use_transactional_fixtures = true
172
+ # self.use_transactional_tests = true
148
173
  #
149
174
  # test "godzilla" do
150
- # assert !Foo.all.empty?
175
+ # assert_not_empty Foo.all
151
176
  # Foo.destroy_all
152
- # assert Foo.all.empty?
177
+ # assert_empty Foo.all
153
178
  # end
154
179
  #
155
180
  # test "godzilla aftermath" do
156
- # assert !Foo.all.empty?
181
+ # assert_not_empty Foo.all
157
182
  # end
158
183
  # end
159
184
  #
160
- # If you preload your test database with all fixture data (probably in the rake task) and use
161
- # transactional fixtures, then you may omit all fixtures declarations in your test cases since
185
+ # If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
186
+ # and use transactional tests, then you may omit all fixtures declarations in your test cases since
162
187
  # all the data's already there and every case rolls back its changes.
163
188
  #
164
189
  # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to
165
190
  # true. This will provide access to fixture data for every table that has been loaded through
166
191
  # fixtures (depending on the value of +use_instantiated_fixtures+).
167
192
  #
168
- # When *not* to use transactional fixtures:
193
+ # When *not* to use transactional tests:
169
194
  #
170
195
  # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until
171
196
  # all parent transactions commit, particularly, the fixtures transaction which is begun in setup
@@ -394,207 +419,227 @@ module ActiveRecord
394
419
  # <<: *DEFAULTS
395
420
  #
396
421
  # Any fixture labeled "DEFAULTS" is safely ignored.
422
+ #
423
+ # == Configure the fixture model class
424
+ #
425
+ # It's possible to set the fixture's model class directly in the YAML file.
426
+ # This is helpful when fixtures are loaded outside tests and
427
+ # +set_fixture_class+ is not available (e.g.
428
+ # when running <tt>rails db:fixtures:load</tt>).
429
+ #
430
+ # _fixture:
431
+ # model_class: User
432
+ # david:
433
+ # name: David
434
+ #
435
+ # Any fixtures labeled "_fixture" are safely ignored.
397
436
  class FixtureSet
398
437
  #--
399
438
  # An instance of FixtureSet is normally stored in a single YAML file and
400
439
  # possibly in a folder with the same name.
401
440
  #++
402
441
 
403
- MAX_ID = 2 ** 30 - 1
442
+ MAX_ID = 2**30 - 1
404
443
 
405
- @@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
444
+ @@all_cached_fixtures = Hash.new { |h, k| h[k] = {} }
406
445
 
407
- def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
408
- config.pluralize_table_names ?
409
- fixture_set_name.singularize.camelize :
410
- fixture_set_name.camelize
411
- end
412
-
413
- def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
414
- "#{ config.table_name_prefix }"\
415
- "#{ fixture_set_name.tr('/', '_') }"\
416
- "#{ config.table_name_suffix }".to_sym
417
- end
446
+ cattr_accessor :all_loaded_fixtures, default: {}
418
447
 
419
- def self.reset_cache
420
- @@all_cached_fixtures.clear
421
- end
422
-
423
- def self.cache_for_connection(connection)
424
- @@all_cached_fixtures[connection]
425
- end
448
+ class ClassCache
449
+ def initialize(class_names, config)
450
+ @class_names = class_names.stringify_keys
451
+ @config = config
426
452
 
427
- def self.fixture_is_cached?(connection, table_name)
428
- cache_for_connection(connection)[table_name]
429
- end
453
+ # Remove string values that aren't constants or subclasses of AR
454
+ @class_names.delete_if do |klass_name, klass|
455
+ !insert_class(@class_names, klass_name, klass)
456
+ end
457
+ end
430
458
 
431
- def self.cached_fixtures(connection, keys_to_fetch = nil)
432
- if keys_to_fetch
433
- cache_for_connection(connection).values_at(*keys_to_fetch)
434
- else
435
- cache_for_connection(connection).values
459
+ def [](fs_name)
460
+ @class_names.fetch(fs_name) do
461
+ klass = default_fixture_model(fs_name, @config).safe_constantize
462
+ insert_class(@class_names, fs_name, klass)
463
+ end
436
464
  end
437
- end
438
465
 
439
- def self.cache_fixtures(connection, fixtures_map)
440
- cache_for_connection(connection).update(fixtures_map)
441
- end
466
+ private
442
467
 
443
- def self.instantiate_fixtures(object, fixture_set, load_instances = true)
444
- if load_instances
445
- fixture_set.each do |fixture_name, fixture|
446
- begin
447
- object.instance_variable_set "@#{fixture_name}", fixture.find
448
- rescue FixtureClassNotFound
449
- nil
468
+ def insert_class(class_names, name, klass)
469
+ # We only want to deal with AR objects.
470
+ if klass && klass < ActiveRecord::Base
471
+ class_names[name] = klass
472
+ else
473
+ class_names[name] = nil
450
474
  end
451
475
  end
452
- end
453
- end
454
476
 
455
- def self.instantiate_all_loaded_fixtures(object, load_instances = true)
456
- all_loaded_fixtures.each_value do |fixture_set|
457
- instantiate_fixtures(object, fixture_set, load_instances)
458
- end
477
+ def default_fixture_model(fs_name, config)
478
+ ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
479
+ end
459
480
  end
460
481
 
461
- cattr_accessor :all_loaded_fixtures
462
- self.all_loaded_fixtures = {}
482
+ class << self
483
+ def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
484
+ config.pluralize_table_names ?
485
+ fixture_set_name.singularize.camelize :
486
+ fixture_set_name.camelize
487
+ end
463
488
 
464
- class ClassCache
465
- def initialize(class_names, config)
466
- @class_names = class_names.stringify_keys
467
- @config = config
489
+ def default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
490
+ "#{ config.table_name_prefix }"\
491
+ "#{ fixture_set_name.tr('/', '_') }"\
492
+ "#{ config.table_name_suffix }".to_sym
493
+ end
468
494
 
469
- # Remove string values that aren't constants or subclasses of AR
470
- @class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
495
+ def reset_cache
496
+ @@all_cached_fixtures.clear
471
497
  end
472
498
 
473
- def [](fs_name)
474
- @class_names.fetch(fs_name) {
475
- klass = default_fixture_model(fs_name, @config).safe_constantize
476
- insert_class(@class_names, fs_name, klass)
477
- }
499
+ def cache_for_connection(connection)
500
+ @@all_cached_fixtures[connection]
478
501
  end
479
502
 
480
- private
503
+ def fixture_is_cached?(connection, table_name)
504
+ cache_for_connection(connection)[table_name]
505
+ end
481
506
 
482
- def insert_class(class_names, name, klass)
483
- # We only want to deal with AR objects.
484
- if klass && klass < ActiveRecord::Base
485
- class_names[name] = klass
507
+ def cached_fixtures(connection, keys_to_fetch = nil)
508
+ if keys_to_fetch
509
+ cache_for_connection(connection).values_at(*keys_to_fetch)
486
510
  else
487
- class_names[name] = nil
511
+ cache_for_connection(connection).values
488
512
  end
489
513
  end
490
514
 
491
- def default_fixture_model(fs_name, config)
492
- ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
515
+ def cache_fixtures(connection, fixtures_map)
516
+ cache_for_connection(connection).update(fixtures_map)
493
517
  end
494
- end
495
518
 
496
- def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
497
- fixture_set_names = Array(fixture_set_names).map(&:to_s)
498
- class_names = ClassCache.new class_names, config
519
+ def instantiate_fixtures(object, fixture_set, load_instances = true)
520
+ return unless load_instances
521
+ fixture_set.each do |fixture_name, fixture|
522
+ object.instance_variable_set "@#{fixture_name}", fixture.find
523
+ rescue FixtureClassNotFound
524
+ nil
525
+ end
526
+ end
499
527
 
500
- # FIXME: Apparently JK uses this.
501
- connection = block_given? ? yield : ActiveRecord::Base.connection
528
+ def instantiate_all_loaded_fixtures(object, load_instances = true)
529
+ all_loaded_fixtures.each_value do |fixture_set|
530
+ instantiate_fixtures(object, fixture_set, load_instances)
531
+ end
532
+ end
502
533
 
503
- files_to_read = fixture_set_names.reject { |fs_name|
504
- fixture_is_cached?(connection, fs_name)
505
- }
534
+ def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
535
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
536
+ class_names = ClassCache.new class_names, config
506
537
 
507
- unless files_to_read.empty?
508
- connection.disable_referential_integrity do
509
- fixtures_map = {}
538
+ # FIXME: Apparently JK uses this.
539
+ connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
540
+
541
+ fixture_files_to_read = fixture_set_names.reject do |fs_name|
542
+ fixture_is_cached?(connection.call, fs_name)
543
+ end
544
+
545
+ if fixture_files_to_read.any?
546
+ fixtures_map = read_and_insert(
547
+ fixtures_directory,
548
+ fixture_files_to_read,
549
+ class_names,
550
+ connection,
551
+ )
552
+ cache_fixtures(connection.call, fixtures_map)
553
+ end
554
+ cached_fixtures(connection.call, fixture_set_names)
555
+ end
556
+
557
+ # Returns a consistent, platform-independent identifier for +label+.
558
+ # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
559
+ def identify(label, column_type = :integer)
560
+ if column_type == :uuid
561
+ Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
562
+ else
563
+ Zlib.crc32(label.to_s) % MAX_ID
564
+ end
565
+ end
510
566
 
511
- fixture_sets = files_to_read.map do |fs_name|
512
- klass = class_names[fs_name]
513
- conn = klass ? klass.connection : connection
514
- fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
515
- conn,
516
- fs_name,
567
+ # Superclass for the evaluation contexts used by ERB fixtures.
568
+ def context_class
569
+ @context_class ||= Class.new
570
+ end
571
+
572
+ private
573
+
574
+ def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
575
+ fixtures_map = {}
576
+ fixture_sets = fixture_files.map do |fixture_set_name|
577
+ klass = class_names[fixture_set_name]
578
+ fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
579
+ nil,
580
+ fixture_set_name,
517
581
  klass,
518
- ::File.join(fixtures_directory, fs_name))
582
+ ::File.join(fixtures_directory, fixture_set_name)
583
+ )
519
584
  end
585
+ update_all_loaded_fixtures(fixtures_map)
520
586
 
521
- update_all_loaded_fixtures fixtures_map
587
+ insert(fixture_sets, connection)
522
588
 
523
- connection.transaction(:requires_new => true) do
524
- fixture_sets.each do |fs|
525
- conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
526
- table_rows = fs.table_rows
589
+ fixtures_map
590
+ end
527
591
 
528
- table_rows.each_key do |table|
529
- conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
530
- end
592
+ def insert(fixture_sets, connection) # :nodoc:
593
+ fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
594
+ if fixture_set.model_class
595
+ fixture_set.model_class.connection
596
+ else
597
+ connection.call
598
+ end
599
+ end
531
600
 
532
- table_rows.each do |fixture_set_name, rows|
533
- rows.each do |row|
534
- conn.insert_fixture(row, fixture_set_name)
535
- end
536
- end
601
+ fixture_sets_by_connection.each do |conn, set|
602
+ table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
537
603
 
538
- # Cap primary key sequences to max(pk).
539
- if conn.respond_to?(:reset_pk_sequence!)
540
- conn.reset_pk_sequence!(fs.table_name)
604
+ set.each do |fixture_set|
605
+ fixture_set.table_rows.each do |table, rows|
606
+ table_rows_for_connection[table].unshift(*rows)
541
607
  end
542
608
  end
543
- end
544
609
 
545
- cache_fixtures(connection, fixtures_map)
546
- end
547
- end
548
- cached_fixtures(connection, fixture_set_names)
549
- end
610
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
550
611
 
551
- # Returns a consistent, platform-independent identifier for +label+.
552
- # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
553
- def self.identify(label, column_type = :integer)
554
- if column_type == :uuid
555
- Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
556
- else
557
- Zlib.crc32(label.to_s) % MAX_ID
558
- end
559
- end
560
-
561
- # Superclass for the evaluation contexts used by ERB fixtures.
562
- def self.context_class
563
- @context_class ||= Class.new
564
- end
612
+ # Cap primary key sequences to max(pk).
613
+ if conn.respond_to?(:reset_pk_sequence!)
614
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
615
+ end
616
+ end
617
+ end
565
618
 
566
- def self.update_all_loaded_fixtures(fixtures_map) # :nodoc:
567
- all_loaded_fixtures.update(fixtures_map)
619
+ def update_all_loaded_fixtures(fixtures_map) # :nodoc:
620
+ all_loaded_fixtures.update(fixtures_map)
621
+ end
568
622
  end
569
623
 
570
624
  attr_reader :table_name, :name, :fixtures, :model_class, :config
571
625
 
572
- def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
626
+ def initialize(_, name, class_name, path, config = ActiveRecord::Base)
573
627
  @name = name
574
628
  @path = path
575
629
  @config = config
576
- @model_class = nil
577
630
 
578
- if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
579
- @model_class = class_name
580
- else
581
- @model_class = class_name.safe_constantize if class_name
582
- end
583
-
584
- @connection = connection
631
+ self.model_class = class_name
585
632
 
586
- @table_name = ( model_class.respond_to?(:table_name) ?
587
- model_class.table_name :
588
- self.class.default_fixture_table_name(name, config) )
633
+ @fixtures = read_fixture_files(path)
589
634
 
590
- @fixtures = read_fixture_files path, @model_class
635
+ @table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
591
636
  end
592
637
 
593
638
  def [](x)
594
639
  fixtures[x]
595
640
  end
596
641
 
597
- def []=(k,v)
642
+ def []=(k, v)
598
643
  fixtures[k] = v
599
644
  end
600
645
 
@@ -609,154 +654,38 @@ module ActiveRecord
609
654
  # Returns a hash of rows to be inserted. The key is the table, the value is
610
655
  # a list of rows to insert to that table.
611
656
  def table_rows
612
- now = config.default_timezone == :utc ? Time.now.utc : Time.now
613
- now = now.to_s(:db)
614
-
615
657
  # allow a standard key to be used for doing defaults in YAML
616
- fixtures.delete('DEFAULTS')
617
-
618
- # track any join tables we need to insert later
619
- rows = Hash.new { |h,table| h[table] = [] }
620
-
621
- rows[table_name] = fixtures.map do |label, fixture|
622
- row = fixture.to_hash
623
-
624
- if model_class
625
- # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
626
- if model_class.record_timestamps
627
- timestamp_column_names.each do |c_name|
628
- row[c_name] = now unless row.key?(c_name)
629
- end
630
- end
631
-
632
- # interpolate the fixture label
633
- row.each do |key, value|
634
- row[key] = value.gsub("$LABEL", label.to_s) if value.is_a?(String)
635
- end
636
-
637
- # generate a primary key if necessary
638
- if has_primary_key_column? && !row.include?(primary_key_name)
639
- row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
640
- end
641
-
642
- # If STI is used, find the correct subclass for association reflection
643
- reflection_class =
644
- if row.include?(inheritance_column_name)
645
- row[inheritance_column_name].constantize rescue model_class
646
- else
647
- model_class
648
- end
649
-
650
- reflection_class._reflections.each_value do |association|
651
- case association.macro
652
- when :belongs_to
653
- # Do not replace association name with association foreign key if they are named the same
654
- fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
658
+ fixtures.delete("DEFAULTS")
655
659
 
656
- if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
657
- if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
658
- # support polymorphic belongs_to as "label (Type)"
659
- row[association.foreign_type] = $1
660
- end
661
-
662
- fk_type = reflection_class.columns_hash[fk_name].type
663
- row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
664
- end
665
- when :has_many
666
- if association.options[:through]
667
- add_join_records(rows, row, HasManyThroughProxy.new(association))
668
- end
669
- end
670
- end
671
- end
672
-
673
- row
674
- end
675
- rows
676
- end
677
-
678
- class ReflectionProxy # :nodoc:
679
- def initialize(association)
680
- @association = association
681
- end
682
-
683
- def join_table
684
- @association.join_table
685
- end
686
-
687
- def name
688
- @association.name
689
- end
690
-
691
- def primary_key_type
692
- @association.klass.column_types[@association.klass.primary_key].type
693
- end
694
- end
695
-
696
- class HasManyThroughProxy < ReflectionProxy # :nodoc:
697
- def rhs_key
698
- @association.foreign_key
699
- end
700
-
701
- def lhs_key
702
- @association.through_reflection.foreign_key
703
- end
704
-
705
- def join_table
706
- @association.through_reflection.table_name
707
- end
660
+ TableRows.new(
661
+ table_name,
662
+ model_class: model_class,
663
+ fixtures: fixtures,
664
+ config: config,
665
+ ).to_hash
708
666
  end
709
667
 
710
668
  private
711
- def primary_key_name
712
- @primary_key_name ||= model_class && model_class.primary_key
713
- end
714
-
715
- def primary_key_type
716
- @primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
717
- end
718
669
 
719
- def add_join_records(rows, row, association)
720
- # This is the case when the join table has no fixtures file
721
- if (targets = row.delete(association.name.to_s))
722
- table_name = association.join_table
723
- column_type = association.primary_key_type
724
- lhs_key = association.lhs_key
725
- rhs_key = association.rhs_key
726
-
727
- targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
728
- rows[table_name].concat targets.map { |target|
729
- { lhs_key => row[primary_key_name],
730
- rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
731
- }
670
+ def model_class=(class_name)
671
+ if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
672
+ @model_class = class_name
673
+ else
674
+ @model_class = class_name.safe_constantize if class_name
732
675
  end
733
676
  end
734
677
 
735
- def has_primary_key_column?
736
- @has_primary_key_column ||= primary_key_name &&
737
- model_class.columns.any? { |c| c.name == primary_key_name }
738
- end
739
-
740
- def timestamp_column_names
741
- @timestamp_column_names ||=
742
- %w(created_at created_on updated_at updated_on) & column_names
743
- end
744
-
745
- def inheritance_column_name
746
- @inheritance_column_name ||= model_class && model_class.inheritance_column
747
- end
748
-
749
- def column_names
750
- @column_names ||= @connection.columns(@table_name).collect { |c| c.name }
751
- end
752
-
753
- def read_fixture_files(path, model_class)
678
+ # Loads the fixtures from the YAML file at +path+.
679
+ # If the file sets the +model_class+ and current instance value is not set,
680
+ # it uses the file value.
681
+ def read_fixture_files(path)
754
682
  yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
755
683
  ::File.file?(f)
756
684
  } + [yaml_file_path(path)]
757
685
 
758
686
  yaml_files.each_with_object({}) do |file, fixtures|
759
687
  FixtureSet::File.open(file) do |fh|
688
+ self.model_class ||= fh.model_class if fh.model_class
760
689
  fh.each do |fixture_name, row|
761
690
  fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
762
691
  end
@@ -767,15 +696,8 @@ module ActiveRecord
767
696
  def yaml_file_path(path)
768
697
  "#{path}.yml"
769
698
  end
770
-
771
699
  end
772
700
 
773
- #--
774
- # Deprecate 'Fixtures' in favor of 'FixtureSet'.
775
- #++
776
- # :nodoc:
777
- Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
778
-
779
701
  class Fixture #:nodoc:
780
702
  include Enumerable
781
703
 
@@ -807,202 +729,9 @@ module ActiveRecord
807
729
  alias :to_hash :fixture
808
730
 
809
731
  def find
810
- if model_class
811
- model_class.unscoped do
812
- model_class.find(fixture[model_class.primary_key])
813
- end
814
- else
815
- raise FixtureClassNotFound, "No class attached to find."
816
- end
817
- end
818
- end
819
- end
820
-
821
- module ActiveRecord
822
- module TestFixtures
823
- extend ActiveSupport::Concern
824
-
825
- def before_setup
826
- setup_fixtures
827
- super
828
- end
829
-
830
- def after_teardown
831
- super
832
- teardown_fixtures
833
- end
834
-
835
- included do
836
- class_attribute :fixture_path, :instance_writer => false
837
- class_attribute :fixture_table_names
838
- class_attribute :fixture_class_names
839
- class_attribute :use_transactional_fixtures
840
- class_attribute :use_instantiated_fixtures # true, false, or :no_instances
841
- class_attribute :pre_loaded_fixtures
842
- class_attribute :config
843
-
844
- self.fixture_table_names = []
845
- self.use_transactional_fixtures = true
846
- self.use_instantiated_fixtures = false
847
- self.pre_loaded_fixtures = false
848
- self.config = ActiveRecord::Base
849
-
850
- self.fixture_class_names = Hash.new do |h, fixture_set_name|
851
- h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name, self.config)
852
- end
853
- end
854
-
855
- module ClassMethods
856
- # Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
857
- #
858
- # Examples:
859
- #
860
- # set_fixture_class some_fixture: SomeModel,
861
- # 'namespaced/fixture' => Another::Model
862
- #
863
- # The keys must be the fixture names, that coincide with the short paths to the fixture files.
864
- def set_fixture_class(class_names = {})
865
- self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
866
- end
867
-
868
- def fixtures(*fixture_set_names)
869
- if fixture_set_names.first == :all
870
- fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
871
- fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
872
- else
873
- fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
874
- end
875
-
876
- self.fixture_table_names |= fixture_set_names
877
- setup_fixture_accessors(fixture_set_names)
878
- end
879
-
880
- def setup_fixture_accessors(fixture_set_names = nil)
881
- fixture_set_names = Array(fixture_set_names || fixture_table_names)
882
- methods = Module.new do
883
- fixture_set_names.each do |fs_name|
884
- fs_name = fs_name.to_s
885
- accessor_name = fs_name.tr('/', '_').to_sym
886
-
887
- define_method(accessor_name) do |*fixture_names|
888
- force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
889
-
890
- @fixture_cache[fs_name] ||= {}
891
-
892
- instances = fixture_names.map do |f_name|
893
- f_name = f_name.to_s
894
- @fixture_cache[fs_name].delete(f_name) if force_reload
895
-
896
- if @loaded_fixtures[fs_name][f_name]
897
- @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
898
- else
899
- raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
900
- end
901
- end
902
-
903
- instances.size == 1 ? instances.first : instances
904
- end
905
- private accessor_name
906
- end
907
- end
908
- include methods
909
- end
910
-
911
- def uses_transaction(*methods)
912
- @uses_transaction = [] unless defined?(@uses_transaction)
913
- @uses_transaction.concat methods.map { |m| m.to_s }
914
- end
915
-
916
- def uses_transaction?(method)
917
- @uses_transaction = [] unless defined?(@uses_transaction)
918
- @uses_transaction.include?(method.to_s)
919
- end
920
- end
921
-
922
- def run_in_transaction?
923
- use_transactional_fixtures &&
924
- !self.class.uses_transaction?(method_name)
925
- end
926
-
927
- def setup_fixtures(config = ActiveRecord::Base)
928
- if pre_loaded_fixtures && !use_transactional_fixtures
929
- raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
930
- end
931
-
932
- @fixture_cache = {}
933
- @fixture_connections = []
934
- @@already_loaded_fixtures ||= {}
935
-
936
- # Load fixtures once and begin transaction.
937
- if run_in_transaction?
938
- if @@already_loaded_fixtures[self.class]
939
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
940
- else
941
- @loaded_fixtures = load_fixtures(config)
942
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
943
- end
944
- @fixture_connections = enlist_fixture_connections
945
- @fixture_connections.each do |connection|
946
- connection.begin_transaction joinable: false
947
- end
948
- # Load fixtures for every test.
949
- else
950
- ActiveRecord::FixtureSet.reset_cache
951
- @@already_loaded_fixtures[self.class] = nil
952
- @loaded_fixtures = load_fixtures(config)
953
- end
954
-
955
- # Instantiate fixtures for every test if requested.
956
- instantiate_fixtures if use_instantiated_fixtures
957
- end
958
-
959
- def teardown_fixtures
960
- # Rollback changes if a transaction is active.
961
- if run_in_transaction?
962
- @fixture_connections.each do |connection|
963
- connection.rollback_transaction if connection.transaction_open?
964
- end
965
- @fixture_connections.clear
966
- else
967
- ActiveRecord::FixtureSet.reset_cache
968
- end
969
-
970
- ActiveRecord::Base.clear_active_connections!
971
- end
972
-
973
- def enlist_fixture_connections
974
- ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
975
- end
976
-
977
- private
978
- def load_fixtures(config)
979
- fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
980
- Hash[fixtures.map { |f| [f.name, f] }]
981
- end
982
-
983
- def instantiate_fixtures
984
- if pre_loaded_fixtures
985
- raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
986
- ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
987
- else
988
- raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
989
- @loaded_fixtures.each_value do |fixture_set|
990
- ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
991
- end
992
- end
993
- end
994
-
995
- def load_instances?
996
- use_instantiated_fixtures != :no_instances
997
- end
998
- end
999
- end
1000
-
1001
- class ActiveRecord::FixtureSet::RenderContext # :nodoc:
1002
- def self.create_subclass
1003
- Class.new ActiveRecord::FixtureSet.context_class do
1004
- def get_binding
1005
- binding()
732
+ raise FixtureClassNotFound, "No class attached to find." unless model_class
733
+ model_class.unscoped do
734
+ model_class.find(fixture[model_class.primary_key])
1006
735
  end
1007
736
  end
1008
737
  end