activerecord 6.0.0 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -6,21 +6,23 @@ require "zlib"
6
6
  require "set"
7
7
  require "active_support/dependencies"
8
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
9
  require "active_record/test_fixtures"
13
- require "active_record/errors"
14
10
 
15
11
  module ActiveRecord
16
- class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
12
+ class FixtureClassNotFound < ActiveRecord::ActiveRecordError # :nodoc:
17
13
  end
18
14
 
15
+ # = Active Record \Fixtures
16
+ #
19
17
  # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
20
18
  #
21
- # They are stored in YAML files, one file per model, which are placed in the directory
22
- # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
23
- # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
19
+ # They are stored in YAML files, one file per model, which are by default placed in either
20
+ # <tt><your-rails-app>/test/fixtures/</tt> or in the <tt>test/fixtures</tt>
21
+ # folder under any of your application's engines.
22
+ #
23
+ # The location can also be changed with ActiveSupport::TestCase.fixture_paths=,
24
+ # once you have <tt>require "rails/test_help"</tt> in your +test_helper.rb+.
25
+ #
24
26
  # The fixture file ends with the +.yml+ file extension, for example:
25
27
  # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
26
28
  #
@@ -36,14 +38,21 @@ module ActiveRecord
36
38
  # name: Google
37
39
  # url: http://www.google.com
38
40
  #
39
- # This fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and
41
+ # This fixture file includes two fixtures. Each YAML fixture (i.e. record) is given a name and
40
42
  # is followed by an indented list of key/value pairs in the "key: value" format. Records are
41
43
  # separated by a blank line for your viewing pleasure.
42
44
  #
43
- # Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
44
- # See http://yaml.org/type/omap.html
45
- # for the specification. You will need ordered fixtures when you have foreign key constraints
46
- # on keys in the same table. This is commonly needed for tree structures. Example:
45
+ # == Ordering
46
+ #
47
+ # Fixtures by default are unordered. This is because the maps in YAML are unordered.
48
+ #
49
+ # If you want ordered fixtures, use the omap YAML type.
50
+ # See https://yaml.org/type/omap.html for the specification.
51
+ #
52
+ # You will need ordered fixtures when you have foreign key constraints
53
+ # on keys in the same table. This is commonly needed for tree structures.
54
+ #
55
+ # For example:
47
56
  #
48
57
  # --- !omap
49
58
  # - parent:
@@ -55,12 +64,12 @@ module ActiveRecord
55
64
  # parent_id: 1
56
65
  # title: Child
57
66
  #
58
- # = Using Fixtures in Test Cases
67
+ # == Using Fixtures in Test Cases
59
68
  #
60
69
  # Since fixtures are a testing construct, we use them in our unit and functional tests. There
61
70
  # are two ways to use the fixtures, but first let's take a look at a sample unit test:
62
71
  #
63
- # require 'test_helper'
72
+ # require "test_helper"
64
73
  #
65
74
  # class WebSiteTest < ActiveSupport::TestCase
66
75
  # test "web_site_count" do
@@ -101,6 +110,12 @@ module ActiveRecord
101
110
  # assert_raise(StandardError) { web_sites(:reddit) }
102
111
  # end
103
112
  #
113
+ # If the model names conflicts with a +TestCase+ methods, you can use the generic +fixture+ accessor
114
+ #
115
+ # test "generic find" do
116
+ # assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
117
+ # end
118
+ #
104
119
  # Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the
105
120
  # following tests:
106
121
  #
@@ -125,7 +140,7 @@ module ActiveRecord
125
140
  # traversed in the database to create the fixture hash and/or instance variables. This is expensive for
126
141
  # large sets of fixtured data.
127
142
  #
128
- # = Dynamic fixtures with ERB
143
+ # == Dynamic fixtures with \ERB
129
144
  #
130
145
  # Sometimes you don't care about the content of the fixtures as much as you care about the volume.
131
146
  # In these cases, you can mix ERB in with your YAML fixtures to create a bunch of fixtures for load
@@ -153,7 +168,7 @@ module ActiveRecord
153
168
  # - define a helper method in <tt>test_helper.rb</tt>
154
169
  # module FixtureFileHelpers
155
170
  # def file_sha(path)
156
- # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
171
+ # OpenSSL::Digest::SHA256.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
157
172
  # end
158
173
  # end
159
174
  # ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers
@@ -163,7 +178,7 @@ module ActiveRecord
163
178
  # name: kitten.png
164
179
  # sha: <%= file_sha 'files/kitten.png' %>
165
180
  #
166
- # = Transactional Tests
181
+ # == Transactional Tests
167
182
  #
168
183
  # Test cases can use begin+rollback to isolate their changes to the database instead of having to
169
184
  # delete+insert for every test case.
@@ -182,7 +197,7 @@ module ActiveRecord
182
197
  # end
183
198
  # end
184
199
  #
185
- # If you preload your test database with all fixture data (probably by running `rails db:fixtures:load`)
200
+ # If you preload your test database with all fixture data (probably by running <tt>bin/rails db:fixtures:load</tt>)
186
201
  # and use transactional tests, then you may omit all fixtures declarations in your test cases since
187
202
  # all the data's already there and every case rolls back its changes.
188
203
  #
@@ -199,7 +214,7 @@ module ActiveRecord
199
214
  # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
200
215
  # Use InnoDB, MaxDB, or NDB instead.
201
216
  #
202
- # = Advanced Fixtures
217
+ # == Advanced Fixtures
203
218
  #
204
219
  # Fixtures that don't specify an ID get some extra features:
205
220
  #
@@ -213,7 +228,7 @@ module ActiveRecord
213
228
  # * Fixture label interpolation
214
229
  # * Support for YAML defaults
215
230
  #
216
- # == Stable, Autogenerated IDs
231
+ # === Stable, Autogenerated IDs
217
232
  #
218
233
  # Here, have a monkey fixture:
219
234
  #
@@ -242,13 +257,13 @@ module ActiveRecord
242
257
  # The generated ID for a given label is constant, so we can discover
243
258
  # any fixture's ID without loading anything, as long as we know the label.
244
259
  #
245
- # == Label references for associations (belongs_to, has_one, has_many)
260
+ # === Label references for associations (+belongs_to+, +has_one+, +has_many+)
246
261
  #
247
262
  # Specifying foreign keys in fixtures can be very fragile, not to
248
263
  # mention difficult to read. Since Active Record can figure out the ID of
249
264
  # any fixture from its label, you can specify FK's by label instead of ID.
250
265
  #
251
- # === belongs_to
266
+ # ==== +belongs_to+
252
267
  #
253
268
  # Let's break out some more monkeys and pirates.
254
269
  #
@@ -259,6 +274,8 @@ module ActiveRecord
259
274
  # name: Reginald the Pirate
260
275
  # monkey_id: 1
261
276
  #
277
+ # <code></code>
278
+ #
262
279
  # ### in monkeys.yml
263
280
  #
264
281
  # george:
@@ -276,6 +293,8 @@ module ActiveRecord
276
293
  # name: Reginald the Pirate
277
294
  # monkey: george
278
295
  #
296
+ # <code></code>
297
+ #
279
298
  # ### in monkeys.yml
280
299
  #
281
300
  # george:
@@ -287,7 +306,7 @@ module ActiveRecord
287
306
  # a target *label* for the *association* (monkey: george) rather than
288
307
  # a target *id* for the *FK* (<tt>monkey_id: 1</tt>).
289
308
  #
290
- # ==== Polymorphic belongs_to
309
+ # ==== Polymorphic +belongs_to+
291
310
  #
292
311
  # Supporting polymorphic relationships is a little bit more complicated, since
293
312
  # Active Record needs to know what type your association is pointing at. Something
@@ -297,6 +316,8 @@ module ActiveRecord
297
316
  #
298
317
  # belongs_to :eater, polymorphic: true
299
318
  #
319
+ # <code></code>
320
+ #
300
321
  # ### in fruits.yml
301
322
  #
302
323
  # apple:
@@ -312,9 +333,9 @@ module ActiveRecord
312
333
  #
313
334
  # Just provide the polymorphic target type and Active Record will take care of the rest.
314
335
  #
315
- # === has_and_belongs_to_many
336
+ # ==== +has_and_belongs_to_many+ or <tt>has_many :through</tt>
316
337
  #
317
- # Time to give our monkey some fruit.
338
+ # \Time to give our monkey some fruit.
318
339
  #
319
340
  # ### in monkeys.yml
320
341
  #
@@ -322,6 +343,8 @@ module ActiveRecord
322
343
  # id: 1
323
344
  # name: George the Monkey
324
345
  #
346
+ # <code></code>
347
+ #
325
348
  # ### in fruits.yml
326
349
  #
327
350
  # apple:
@@ -336,6 +359,8 @@ module ActiveRecord
336
359
  # id: 3
337
360
  # name: grape
338
361
  #
362
+ # <code></code>
363
+ #
339
364
  # ### in fruits_monkeys.yml
340
365
  #
341
366
  # apple_george:
@@ -359,6 +384,8 @@ module ActiveRecord
359
384
  # name: George the Monkey
360
385
  # fruits: apple, orange, grape
361
386
  #
387
+ # <code></code>
388
+ #
362
389
  # ### in fruits.yml
363
390
  #
364
391
  # apple:
@@ -376,7 +403,7 @@ module ActiveRecord
376
403
  # the fixture's model class and discovers the +has_and_belongs_to_many+
377
404
  # associations.
378
405
  #
379
- # == Autofilled Timestamp Columns
406
+ # === Autofilled \Timestamp Columns
380
407
  #
381
408
  # If your table/model specifies any of Active Record's
382
409
  # standard timestamp columns (+created_at+, +created_on+, +updated_at+, +updated_on+),
@@ -384,7 +411,7 @@ module ActiveRecord
384
411
  #
385
412
  # If you've set specific values, they'll be left alone.
386
413
  #
387
- # == Fixture label interpolation
414
+ # === Fixture label interpolation
388
415
  #
389
416
  # The label of the current fixture is always available as a column value:
390
417
  #
@@ -401,14 +428,18 @@ module ActiveRecord
401
428
  # monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
402
429
  # pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
403
430
  #
404
- # == Support for YAML defaults
431
+ # If the model uses UUID values for identifiers, add the +:uuid+ argument:
432
+ #
433
+ # ActiveRecord::FixtureSet.identify(:boaty_mcboatface, :uuid)
434
+ #
435
+ # === Support for YAML defaults
405
436
  #
406
437
  # You can set and reuse defaults in your fixtures YAML file.
407
438
  # This is the same technique used in the +database.yml+ file to specify
408
439
  # defaults:
409
440
  #
410
441
  # DEFAULTS: &DEFAULTS
411
- # created_on: <%= 3.weeks.ago.to_s(:db) %>
442
+ # created_on: <%= 3.weeks.ago.to_fs(:db) %>
412
443
  #
413
444
  # first:
414
445
  # name: Smurf
@@ -420,12 +451,74 @@ module ActiveRecord
420
451
  #
421
452
  # Any fixture labeled "DEFAULTS" is safely ignored.
422
453
  #
454
+ # Besides using "DEFAULTS", you can also specify what fixtures will
455
+ # be ignored by setting "ignore" in "_fixture" section.
456
+ #
457
+ # # users.yml
458
+ # _fixture:
459
+ # ignore:
460
+ # - base
461
+ # # or use "ignore: base" when there is only one fixture that needs to be ignored.
462
+ #
463
+ # base: &base
464
+ # admin: false
465
+ # introduction: "This is a default description"
466
+ #
467
+ # admin:
468
+ # <<: *base
469
+ # admin: true
470
+ #
471
+ # visitor:
472
+ # <<: *base
473
+ #
474
+ # In the above example, 'base' will be ignored when creating fixtures.
475
+ # This can be used for common attributes inheriting.
476
+ #
477
+ # == Composite Primary Key Fixtures
478
+ #
479
+ # Fixtures for composite primary key tables are fairly similar to normal tables.
480
+ # When using an id column, the column may be omitted as usual:
481
+ #
482
+ # # app/models/book.rb
483
+ # class Book < ApplicationRecord
484
+ # self.primary_key = [:author_id, :id]
485
+ # belongs_to :author
486
+ # end
487
+ #
488
+ # <code></code>
489
+ #
490
+ # # books.yml
491
+ # alices_adventure_in_wonderland:
492
+ # author_id: <%= ActiveRecord::FixtureSet.identify(:lewis_carroll) %>
493
+ # title: "Alice's Adventures in Wonderland"
494
+ #
495
+ # However, in order to support composite primary key relationships,
496
+ # you must use the `composite_identify` method:
497
+ #
498
+ # # app/models/book_orders.rb
499
+ # class BookOrder < ApplicationRecord
500
+ # self.primary_key = [:shop_id, :id]
501
+ # belongs_to :order, foreign_key: [:shop_id, :order_id]
502
+ # belongs_to :book, foreign_key: [:author_id, :book_id]
503
+ # end
504
+ #
505
+ # <code></code>
506
+ #
507
+ # # book_orders.yml
508
+ # alices_adventure_in_wonderland_in_books:
509
+ # author: lewis_carroll
510
+ # book_id: <%= ActiveRecord::FixtureSet.composite_identify(
511
+ # :alices_adventure_in_wonderland, Book.primary_key)[:id] %>
512
+ # shop: book_store
513
+ # order_id: <%= ActiveRecord::FixtureSet.composite_identify(
514
+ # :books, Order.primary_key)[:id] %>
515
+ #
423
516
  # == Configure the fixture model class
424
517
  #
425
518
  # It's possible to set the fixture's model class directly in the YAML file.
426
519
  # This is helpful when fixtures are loaded outside tests and
427
520
  # +set_fixture_class+ is not available (e.g.
428
- # when running <tt>rails db:fixtures:load</tt>).
521
+ # when running <tt>bin/rails db:fixtures:load</tt>).
429
522
  #
430
523
  # _fixture:
431
524
  # model_class: User
@@ -434,6 +527,10 @@ module ActiveRecord
434
527
  #
435
528
  # Any fixtures labeled "_fixture" are safely ignored.
436
529
  class FixtureSet
530
+ require "active_record/fixture_set/file"
531
+ require "active_record/fixture_set/render_context"
532
+ require "active_record/fixture_set/table_rows"
533
+
437
534
  #--
438
535
  # An instance of FixtureSet is normally stored in a single YAML file and
439
536
  # possibly in a folder with the same name.
@@ -445,40 +542,6 @@ module ActiveRecord
445
542
 
446
543
  cattr_accessor :all_loaded_fixtures, default: {}
447
544
 
448
- class ClassCache
449
- def initialize(class_names, config)
450
- @class_names = class_names.stringify_keys
451
- @config = config
452
-
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
458
-
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
464
- end
465
-
466
- private
467
-
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
474
- end
475
- end
476
-
477
- def default_fixture_model(fs_name, config)
478
- ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
479
- end
480
- end
481
-
482
545
  class << self
483
546
  def default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
484
547
  config.pluralize_table_names ?
@@ -496,24 +559,24 @@ module ActiveRecord
496
559
  @@all_cached_fixtures.clear
497
560
  end
498
561
 
499
- def cache_for_connection(connection)
500
- @@all_cached_fixtures[connection]
562
+ def cache_for_connection_pool(connection_pool)
563
+ @@all_cached_fixtures[connection_pool]
501
564
  end
502
565
 
503
- def fixture_is_cached?(connection, table_name)
504
- cache_for_connection(connection)[table_name]
566
+ def fixture_is_cached?(connection_pool, table_name)
567
+ cache_for_connection_pool(connection_pool)[table_name]
505
568
  end
506
569
 
507
- def cached_fixtures(connection, keys_to_fetch = nil)
570
+ def cached_fixtures(connection_pool, keys_to_fetch = nil)
508
571
  if keys_to_fetch
509
- cache_for_connection(connection).values_at(*keys_to_fetch)
572
+ cache_for_connection_pool(connection_pool).values_at(*keys_to_fetch)
510
573
  else
511
- cache_for_connection(connection).values
574
+ cache_for_connection_pool(connection_pool).values
512
575
  end
513
576
  end
514
577
 
515
- def cache_fixtures(connection, fixtures_map)
516
- cache_for_connection(connection).update(fixtures_map)
578
+ def cache_fixtures(connection_pool, fixtures_map)
579
+ cache_for_connection_pool(connection_pool).update(fixtures_map)
517
580
  end
518
581
 
519
582
  def instantiate_fixtures(object, fixture_set, load_instances = true)
@@ -531,31 +594,30 @@ module ActiveRecord
531
594
  end
532
595
  end
533
596
 
534
- def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
597
+ def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
535
598
  fixture_set_names = Array(fixture_set_names).map(&:to_s)
536
- class_names = ClassCache.new class_names, config
537
-
538
- # FIXME: Apparently JK uses this.
539
- connection = block_given? ? block : lambda { ActiveRecord::Base.connection }
599
+ class_names.stringify_keys!
540
600
 
601
+ connection_pool = config.connection_pool
541
602
  fixture_files_to_read = fixture_set_names.reject do |fs_name|
542
- fixture_is_cached?(connection.call, fs_name)
603
+ fixture_is_cached?(connection_pool, fs_name)
543
604
  end
544
605
 
545
606
  if fixture_files_to_read.any?
546
607
  fixtures_map = read_and_insert(
547
- fixtures_directory,
608
+ Array(fixtures_directories),
548
609
  fixture_files_to_read,
549
610
  class_names,
550
- connection,
611
+ connection_pool,
551
612
  )
552
- cache_fixtures(connection.call, fixtures_map)
613
+ cache_fixtures(connection_pool, fixtures_map)
553
614
  end
554
- cached_fixtures(connection.call, fixture_set_names)
615
+ cached_fixtures(connection_pool, fixture_set_names)
555
616
  end
556
617
 
557
618
  # 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.
619
+ #
620
+ # \Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
559
621
  def identify(label, column_type = :integer)
560
622
  if column_type == :uuid
561
623
  Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
@@ -564,41 +626,54 @@ module ActiveRecord
564
626
  end
565
627
  end
566
628
 
567
- # Superclass for the evaluation contexts used by ERB fixtures.
629
+ # Returns a consistent, platform-independent hash representing a mapping
630
+ # between the label and the subcomponents of the provided composite key.
631
+ #
632
+ # Example:
633
+ #
634
+ # composite_identify("label", [:a, :b, :c]) # => { a: hash_1, b: hash_2, c: hash_3 }
635
+ def composite_identify(label, key)
636
+ key
637
+ .index_with
638
+ .with_index { |sub_key, index| (identify(label) << index) % MAX_ID }
639
+ .with_indifferent_access
640
+ end
641
+
642
+ # Superclass for the evaluation contexts used by \ERB fixtures.
568
643
  def context_class
569
644
  @context_class ||= Class.new
570
645
  end
571
646
 
572
647
  private
573
-
574
- def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc:
648
+ def read_and_insert(fixtures_directories, fixture_files, class_names, connection_pool) # :nodoc:
575
649
  fixtures_map = {}
650
+ directory_glob = "{#{fixtures_directories.join(",")}}"
576
651
  fixture_sets = fixture_files.map do |fixture_set_name|
577
652
  klass = class_names[fixture_set_name]
578
653
  fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
579
654
  nil,
580
655
  fixture_set_name,
581
656
  klass,
582
- ::File.join(fixtures_directory, fixture_set_name)
657
+ ::File.join(directory_glob, fixture_set_name)
583
658
  )
584
659
  end
585
660
  update_all_loaded_fixtures(fixtures_map)
586
661
 
587
- insert(fixture_sets, connection)
662
+ insert(fixture_sets, connection_pool)
588
663
 
589
664
  fixtures_map
590
665
  end
591
666
 
592
- def insert(fixture_sets, connection) # :nodoc:
593
- fixture_sets_by_connection = fixture_sets.group_by do |fixture_set|
667
+ def insert(fixture_sets, connection_pool) # :nodoc:
668
+ fixture_sets_by_pool = fixture_sets.group_by do |fixture_set|
594
669
  if fixture_set.model_class
595
- fixture_set.model_class.connection
670
+ fixture_set.model_class.connection_pool
596
671
  else
597
- connection.call
672
+ connection_pool
598
673
  end
599
674
  end
600
675
 
601
- fixture_sets_by_connection.each do |conn, set|
676
+ fixture_sets_by_pool.each do |pool, set|
602
677
  table_rows_for_connection = Hash.new { |h, k| h[k] = [] }
603
678
 
604
679
  set.each do |fixture_set|
@@ -607,21 +682,35 @@ module ActiveRecord
607
682
  end
608
683
  end
609
684
 
610
- conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
685
+ pool.with_connection do |conn|
686
+ conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys)
687
+
688
+ check_all_foreign_keys_valid!(conn)
611
689
 
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) }
690
+ # Cap primary key sequences to max(pk).
691
+ if conn.respond_to?(:reset_pk_sequence!)
692
+ set.each { |fs| conn.reset_pk_sequence!(fs.table_name) }
693
+ end
615
694
  end
616
695
  end
617
696
  end
618
697
 
698
+ def check_all_foreign_keys_valid!(conn)
699
+ return unless ActiveRecord.verify_foreign_keys_for_fixtures
700
+
701
+ begin
702
+ conn.check_all_foreign_keys_valid!
703
+ rescue ActiveRecord::StatementInvalid => e
704
+ raise "Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. Error from database:\n\n#{e.message}"
705
+ end
706
+ end
707
+
619
708
  def update_all_loaded_fixtures(fixtures_map) # :nodoc:
620
709
  all_loaded_fixtures.update(fixtures_map)
621
710
  end
622
711
  end
623
712
 
624
- attr_reader :table_name, :name, :fixtures, :model_class, :config
713
+ attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config
625
714
 
626
715
  def initialize(_, name, class_name, path, config = ActiveRecord::Base)
627
716
  @name = name
@@ -629,7 +718,6 @@ module ActiveRecord
629
718
  @config = config
630
719
 
631
720
  self.model_class = class_name
632
-
633
721
  @fixtures = read_fixture_files(path)
634
722
 
635
723
  @table_name = model_class&.table_name || self.class.default_fixture_table_name(name, config)
@@ -654,19 +742,17 @@ module ActiveRecord
654
742
  # Returns a hash of rows to be inserted. The key is the table, the value is
655
743
  # a list of rows to insert to that table.
656
744
  def table_rows
657
- # allow a standard key to be used for doing defaults in YAML
658
- fixtures.delete("DEFAULTS")
745
+ # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section
746
+ fixtures.except!(*ignored_fixtures)
659
747
 
660
748
  TableRows.new(
661
749
  table_name,
662
750
  model_class: model_class,
663
751
  fixtures: fixtures,
664
- config: config,
665
752
  ).to_hash
666
753
  end
667
754
 
668
755
  private
669
-
670
756
  def model_class=(class_name)
671
757
  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
672
758
  @model_class = class_name
@@ -675,17 +761,37 @@ module ActiveRecord
675
761
  end
676
762
  end
677
763
 
764
+ def ignored_fixtures=(base)
765
+ @ignored_fixtures =
766
+ case base
767
+ when Array
768
+ base
769
+ when String
770
+ [base]
771
+ else
772
+ []
773
+ end
774
+
775
+ @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS")
776
+ @ignored_fixtures.compact
777
+ end
778
+
678
779
  # Loads the fixtures from the YAML file at +path+.
679
780
  # If the file sets the +model_class+ and current instance value is not set,
680
781
  # it uses the file value.
782
+
681
783
  def read_fixture_files(path)
682
- yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
784
+ yaml_files = Dir["#{path}{.yml,/{**,*}/*.yml}"].select { |f|
683
785
  ::File.file?(f)
684
- } + [yaml_file_path(path)]
786
+ }
787
+
788
+ raise ArgumentError, "No fixture files found for #{@name}" if yaml_files.empty?
685
789
 
686
790
  yaml_files.each_with_object({}) do |file, fixtures|
687
791
  FixtureSet::File.open(file) do |fh|
688
792
  self.model_class ||= fh.model_class if fh.model_class
793
+ self.model_class ||= default_fixture_model_class
794
+ self.ignored_fixtures ||= fh.ignored_fixtures
689
795
  fh.each do |fixture_name, row|
690
796
  fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
691
797
  end
@@ -693,18 +799,19 @@ module ActiveRecord
693
799
  end
694
800
  end
695
801
 
696
- def yaml_file_path(path)
697
- "#{path}.yml"
802
+ def default_fixture_model_class
803
+ klass = ActiveRecord::FixtureSet.default_fixture_model_name(@name, @config).safe_constantize
804
+ klass if klass && klass < ActiveRecord::Base
698
805
  end
699
806
  end
700
807
 
701
- class Fixture #:nodoc:
808
+ class Fixture # :nodoc:
702
809
  include Enumerable
703
810
 
704
- class FixtureError < StandardError #:nodoc:
811
+ class FixtureError < StandardError # :nodoc:
705
812
  end
706
813
 
707
- class FormatError < FixtureError #:nodoc:
814
+ class FormatError < FixtureError # :nodoc:
708
815
  end
709
816
 
710
817
  attr_reader :model_class, :fixture
@@ -718,8 +825,8 @@ module ActiveRecord
718
825
  model_class.name if model_class
719
826
  end
720
827
 
721
- def each
722
- fixture.each { |item| yield item }
828
+ def each(&block)
829
+ fixture.each(&block)
723
830
  end
724
831
 
725
832
  def [](key)
@@ -730,9 +837,15 @@ module ActiveRecord
730
837
 
731
838
  def find
732
839
  raise FixtureClassNotFound, "No class attached to find." unless model_class
733
- model_class.unscoped do
734
- model_class.find(fixture[model_class.primary_key])
840
+ object = model_class.unscoped do
841
+ pk_clauses = fixture.slice(*Array(model_class.primary_key))
842
+ model_class.find_by!(pk_clauses)
735
843
  end
844
+ # Fixtures can't be eagerly loaded
845
+ object.instance_variable_set(:@strict_loading, false)
846
+ object
736
847
  end
737
848
  end
738
849
  end
850
+
851
+ ActiveSupport.run_load_hooks :active_record_fixture_set, ActiveRecord::FixtureSet