activerecord 5.0.7.2 → 6.1.1

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