activerecord 5.2.8 → 7.0.2

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