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
@@ -7,14 +7,13 @@ module ActiveRecord
7
7
  #
8
8
  # This class is used to dump the database schema for some connection to some
9
9
  # output format (i.e., ActiveRecord::Schema).
10
- class SchemaDumper #:nodoc:
10
+ class SchemaDumper # :nodoc:
11
11
  private_class_method :new
12
12
 
13
13
  ##
14
14
  # :singleton-method:
15
15
  # A list of tables which should not be dumped to the schema.
16
- # Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
17
- # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
16
+ # Acceptable values are strings and regexps.
18
17
  cattr_accessor :ignore_tables, default: []
19
18
 
20
19
  ##
@@ -23,9 +22,29 @@ module ActiveRecord
23
22
  # should not be dumped to db/schema.rb.
24
23
  cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
25
24
 
25
+ ##
26
+ # :singleton-method:
27
+ # Specify a custom regular expression matching check constraints which name
28
+ # should not be dumped to db/schema.rb.
29
+ cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
30
+
31
+ ##
32
+ # :singleton-method:
33
+ # Specify a custom regular expression matching exclusion constraints which name
34
+ # should not be dumped to db/schema.rb.
35
+ cattr_accessor :excl_ignore_pattern, default: /^excl_rails_[0-9a-f]{10}$/
36
+
37
+ ##
38
+ # :singleton-method:
39
+ # Specify a custom regular expression matching unique constraints which name
40
+ # should not be dumped to db/schema.rb.
41
+ cattr_accessor :unique_ignore_pattern, default: /^uniq_rails_[0-9a-f]{10}$/
42
+
26
43
  class << self
27
- def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
28
- connection.create_schema_dumper(generate_options(config)).dump(stream)
44
+ def dump(pool = ActiveRecord::Base.connection_pool, stream = $stdout, config = ActiveRecord::Base)
45
+ pool.with_connection do |connection|
46
+ connection.create_schema_dumper(generate_options(config)).dump(stream)
47
+ end
29
48
  stream
30
49
  end
31
50
 
@@ -40,7 +59,9 @@ module ActiveRecord
40
59
 
41
60
  def dump(stream)
42
61
  header(stream)
62
+ schemas(stream)
43
63
  extensions(stream)
64
+ types(stream)
44
65
  tables(stream)
45
66
  trailer(stream)
46
67
  stream
@@ -51,8 +72,13 @@ module ActiveRecord
51
72
 
52
73
  def initialize(connection, options = {})
53
74
  @connection = connection
54
- @version = connection.migration_context.current_version rescue nil
75
+ @version = connection.pool.migration_context.current_version rescue nil
55
76
  @options = options
77
+ @ignore_tables = [
78
+ ActiveRecord::Base.schema_migrations_table_name,
79
+ ActiveRecord::Base.internal_metadata_table_name,
80
+ self.class.ignore_tables
81
+ ].flatten
56
82
  end
57
83
 
58
84
  # turns 20170404131909 into "2017_04_04_131909"
@@ -67,22 +93,21 @@ module ActiveRecord
67
93
  end
68
94
 
69
95
  def header(stream)
70
- stream.puts <<HEADER
71
- # This file is auto-generated from the current state of the database. Instead
72
- # of editing this file, please use the migrations feature of Active Record to
73
- # incrementally modify your database, and then regenerate this schema definition.
74
- #
75
- # This file is the source Rails uses to define your schema when running `rails
76
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
77
- # be faster and is potentially less error prone than running all of your
78
- # migrations from scratch. Old migrations may fail to apply correctly if those
79
- # migrations use external dependencies or application code.
80
- #
81
- # It's strongly recommended that you check this file into your version control system.
82
-
83
- ActiveRecord::Schema.define(#{define_params}) do
84
-
85
- HEADER
96
+ stream.puts <<~HEADER
97
+ # This file is auto-generated from the current state of the database. Instead
98
+ # of editing this file, please use the migrations feature of Active Record to
99
+ # incrementally modify your database, and then regenerate this schema definition.
100
+ #
101
+ # This file is the source Rails uses to define your schema when running `bin/rails
102
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
103
+ # be faster and is potentially less error prone than running all of your
104
+ # migrations from scratch. Old migrations may fail to apply correctly if those
105
+ # migrations use external dependencies or application code.
106
+ #
107
+ # It's strongly recommended that you check this file into your version control system.
108
+
109
+ ActiveRecord::Schema[#{ActiveRecord::Migration.current_version}].define(#{define_params}) do
110
+ HEADER
86
111
  end
87
112
 
88
113
  def trailer(stream)
@@ -93,18 +118,35 @@ HEADER
93
118
  def extensions(stream)
94
119
  end
95
120
 
121
+ # (enum) types are only supported by PostgreSQL
122
+ def types(stream)
123
+ end
124
+
125
+ # schemas are only supported by PostgreSQL
126
+ def schemas(stream)
127
+ end
128
+
96
129
  def tables(stream)
97
130
  sorted_tables = @connection.tables.sort
98
131
 
99
- sorted_tables.each do |table_name|
100
- table(table_name, stream) unless ignored?(table_name)
132
+ not_ignored_tables = sorted_tables.reject { |table_name| ignored?(table_name) }
133
+
134
+ not_ignored_tables.each_with_index do |table_name, index|
135
+ table(table_name, stream)
136
+ stream.puts if index < not_ignored_tables.count - 1
101
137
  end
102
138
 
103
139
  # dump foreign keys at the end to make sure all dependent tables exist.
104
140
  if @connection.supports_foreign_keys?
105
- sorted_tables.each do |tbl|
106
- foreign_keys(tbl, stream) unless ignored?(tbl)
141
+ foreign_keys_stream = StringIO.new
142
+ not_ignored_tables.each do |tbl|
143
+ foreign_keys(tbl, foreign_keys_stream)
107
144
  end
145
+
146
+ foreign_keys_string = foreign_keys_stream.string
147
+ stream.puts if foreign_keys_string.length > 0
148
+
149
+ stream.print foreign_keys_string
108
150
  end
109
151
  end
110
152
 
@@ -125,7 +167,10 @@ HEADER
125
167
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
126
168
  pkcol = columns.detect { |c| c.name == pk }
127
169
  pkcolspec = column_spec_for_primary_key(pkcol)
128
- if pkcolspec.present?
170
+ unless pkcolspec.empty?
171
+ if pkcolspec != pkcolspec.slice(:id, :default)
172
+ pkcolspec = { id: { type: pkcolspec.delete(:id), **pkcolspec }.compact }
173
+ end
129
174
  tbl.print ", #{format_colspec(pkcolspec)}"
130
175
  end
131
176
  when Array
@@ -145,6 +190,7 @@ HEADER
145
190
  columns.each do |column|
146
191
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
147
192
  next if column.name == pk
193
+
148
194
  type, colspec = column_spec(column)
149
195
  if type.is_a?(Symbol)
150
196
  tbl.print " t.#{type} #{column.name.inspect}"
@@ -156,12 +202,18 @@ HEADER
156
202
  end
157
203
 
158
204
  indexes_in_create(table, tbl)
205
+ remaining = check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
206
+ exclusion_constraints_in_create(table, tbl) if @connection.supports_exclusion_constraints?
207
+ unique_constraints_in_create(table, tbl) if @connection.supports_unique_constraints?
159
208
 
160
209
  tbl.puts " end"
161
- tbl.puts
162
210
 
163
- tbl.rewind
164
- stream.print tbl.read
211
+ if remaining
212
+ tbl.puts
213
+ tbl.print remaining.string
214
+ end
215
+
216
+ stream.print tbl.string
165
217
  rescue => e
166
218
  stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
167
219
  stream.puts "# #{e.message}"
@@ -186,6 +238,18 @@ HEADER
186
238
 
187
239
  def indexes_in_create(table, stream)
188
240
  if (indexes = @connection.indexes(table)).any?
241
+ if @connection.supports_exclusion_constraints? && (exclusion_constraints = @connection.exclusion_constraints(table)).any?
242
+ exclusion_constraint_names = exclusion_constraints.collect(&:name)
243
+
244
+ indexes = indexes.reject { |index| exclusion_constraint_names.include?(index.name) }
245
+ end
246
+
247
+ if @connection.supports_unique_constraints? && (unique_constraints = @connection.unique_constraints(table)).any?
248
+ unique_constraint_names = unique_constraints.collect(&:name)
249
+
250
+ indexes = indexes.reject { |index| unique_constraint_names.include?(index.name) }
251
+ end
252
+
189
253
  index_statements = indexes.map do |index|
190
254
  " t.index #{index_parts(index).join(', ')}"
191
255
  end
@@ -204,11 +268,46 @@ HEADER
204
268
  index_parts << "opclass: #{format_index_parts(index.opclasses)}" if index.opclasses.present?
205
269
  index_parts << "where: #{index.where.inspect}" if index.where
206
270
  index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
271
+ index_parts << "include: #{index.include.inspect}" if index.include
272
+ index_parts << "nulls_not_distinct: #{index.nulls_not_distinct.inspect}" if index.nulls_not_distinct
207
273
  index_parts << "type: #{index.type.inspect}" if index.type
208
274
  index_parts << "comment: #{index.comment.inspect}" if index.comment
209
275
  index_parts
210
276
  end
211
277
 
278
+ def check_constraints_in_create(table, stream)
279
+ if (check_constraints = @connection.check_constraints(table)).any?
280
+ check_valid, check_invalid = check_constraints.partition { |chk| chk.validate? }
281
+
282
+ unless check_valid.empty?
283
+ check_constraint_statements = check_valid.map do |check|
284
+ " t.check_constraint #{check_parts(check).join(', ')}"
285
+ end
286
+
287
+ stream.puts check_constraint_statements.sort.join("\n")
288
+ end
289
+
290
+ unless check_invalid.empty?
291
+ remaining = StringIO.new
292
+ table_name = remove_prefix_and_suffix(table).inspect
293
+
294
+ add_check_constraint_statements = check_invalid.map do |check|
295
+ " add_check_constraint #{([table_name] + check_parts(check)).join(', ')}"
296
+ end
297
+
298
+ remaining.puts add_check_constraint_statements.sort.join("\n")
299
+ remaining
300
+ end
301
+ end
302
+ end
303
+
304
+ def check_parts(check)
305
+ check_parts = [ check.expression.inspect ]
306
+ check_parts << "name: #{check.name.inspect}" if check.export_name_on_schema_dump?
307
+ check_parts << "validate: #{check.validate?.inspect}" unless check.validate?
308
+ check_parts
309
+ end
310
+
212
311
  def foreign_keys(table, stream)
213
312
  if (foreign_keys = @connection.foreign_keys(table)).any?
214
313
  add_foreign_key_statements = foreign_keys.map do |foreign_key|
@@ -217,7 +316,7 @@ HEADER
217
316
  remove_prefix_and_suffix(foreign_key.to_table).inspect,
218
317
  ]
219
318
 
220
- if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
319
+ if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table, "id")
221
320
  parts << "column: #{foreign_key.column.inspect}"
222
321
  end
223
322
 
@@ -231,6 +330,8 @@ HEADER
231
330
 
232
331
  parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
233
332
  parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
333
+ parts << "deferrable: #{foreign_key.deferrable.inspect}" if foreign_key.deferrable
334
+ parts << "validate: #{foreign_key.validate?.inspect}" unless foreign_key.validate?
234
335
 
235
336
  " #{parts.join(', ')}"
236
337
  end
@@ -240,7 +341,9 @@ HEADER
240
341
  end
241
342
 
242
343
  def format_colspec(colspec)
243
- colspec.map { |key, value| "#{key}: #{value}" }.join(", ")
344
+ colspec.map do |key, value|
345
+ "#{key}: #{ value.is_a?(Hash) ? "{ #{format_colspec(value)} }" : value }"
346
+ end.join(", ")
244
347
  end
245
348
 
246
349
  def format_options(options)
@@ -256,13 +359,17 @@ HEADER
256
359
  end
257
360
 
258
361
  def remove_prefix_and_suffix(table)
362
+ # This method appears at the top when profiling active_record test cases run.
363
+ # Avoid costly calculation when there are no prefix and suffix.
364
+ return table if @options[:table_name_prefix].blank? && @options[:table_name_suffix].blank?
365
+
259
366
  prefix = Regexp.escape(@options[:table_name_prefix].to_s)
260
367
  suffix = Regexp.escape(@options[:table_name_suffix].to_s)
261
368
  table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
262
369
  end
263
370
 
264
371
  def ignored?(table_name)
265
- [ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
372
+ @ignore_tables.any? do |ignored|
266
373
  ignored === remove_prefix_and_suffix(table_name)
267
374
  end
268
375
  end
@@ -1,60 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/scoping/default"
4
- require "active_record/scoping/named"
5
-
6
3
  module ActiveRecord
7
4
  # This class is used to create a table that keeps track of which migrations
8
5
  # have been applied to a given database. When a migration is run, its schema
9
- # number is inserted in to the `SchemaMigration.table_name` so it doesn't need
6
+ # number is inserted in to the schema migrations table so it doesn't need
10
7
  # to be executed the next time.
11
- class SchemaMigration < ActiveRecord::Base # :nodoc:
12
- class << self
13
- def _internal?
14
- true
15
- end
8
+ class SchemaMigration # :nodoc:
9
+ class NullSchemaMigration # :nodoc:
10
+ end
11
+
12
+ attr_reader :arel_table
16
13
 
17
- def primary_key
18
- "version"
14
+ def initialize(pool)
15
+ @pool = pool
16
+ @arel_table = Arel::Table.new(table_name)
17
+ end
18
+
19
+ def create_version(version)
20
+ im = Arel::InsertManager.new(arel_table)
21
+ im.insert(arel_table[primary_key] => version)
22
+ @pool.with_connection do |connection|
23
+ connection.insert(im, "#{self.class} Create", primary_key, version)
19
24
  end
25
+ end
20
26
 
21
- def table_name
22
- "#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
27
+ def delete_version(version)
28
+ dm = Arel::DeleteManager.new(arel_table)
29
+ dm.wheres = [arel_table[primary_key].eq(version)]
30
+
31
+ @pool.with_connection do |connection|
32
+ connection.delete(dm, "#{self.class} Destroy")
23
33
  end
34
+ end
24
35
 
25
- def table_exists?
26
- connection.table_exists?(table_name)
36
+ def delete_all_versions
37
+ @pool.with_connection do |connection|
38
+ versions.each do |version|
39
+ delete_version(version)
40
+ end
27
41
  end
42
+ end
43
+
44
+ def primary_key
45
+ "version"
46
+ end
28
47
 
29
- def create_table
30
- unless table_exists?
31
- version_options = connection.internal_string_options_for_primary_key
48
+ def table_name
49
+ "#{ActiveRecord::Base.table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{ActiveRecord::Base.table_name_suffix}"
50
+ end
32
51
 
52
+ def create_table
53
+ @pool.with_connection do |connection|
54
+ unless connection.table_exists?(table_name)
33
55
  connection.create_table(table_name, id: false) do |t|
34
- t.string :version, version_options
56
+ t.string :version, **connection.internal_string_options_for_primary_key
35
57
  end
36
58
  end
37
59
  end
60
+ end
38
61
 
39
- def drop_table
62
+ def drop_table
63
+ @pool.with_connection do |connection|
40
64
  connection.drop_table table_name, if_exists: true
41
65
  end
66
+ end
42
67
 
43
- def normalize_migration_number(number)
44
- "%.3d" % number.to_i
45
- end
68
+ def normalize_migration_number(number)
69
+ "%.3d" % number.to_i
70
+ end
71
+
72
+ def normalized_versions
73
+ versions.map { |v| normalize_migration_number v }
74
+ end
46
75
 
47
- def normalized_versions
48
- all_versions.map { |v| normalize_migration_number v }
76
+ def versions
77
+ sm = Arel::SelectManager.new(arel_table)
78
+ sm.project(arel_table[primary_key])
79
+ sm.order(arel_table[primary_key].asc)
80
+
81
+ @pool.with_connection do |connection|
82
+ connection.select_values(sm, "#{self.class} Load")
49
83
  end
84
+ end
85
+
86
+ def integer_versions
87
+ versions.map(&:to_i)
88
+ end
89
+
90
+ def count
91
+ sm = Arel::SelectManager.new(arel_table)
92
+ sm.project(*Arel::Nodes::Count.new([Arel.star]))
50
93
 
51
- def all_versions
52
- order(:version).pluck(:version)
94
+ @pool.with_connection do |connection|
95
+ connection.select_values(sm, "#{self.class} Count").first
53
96
  end
54
97
  end
55
98
 
56
- def version
57
- super.to_i
99
+ def table_exists?
100
+ @pool.with_connection do |connection|
101
+ connection.data_source_exists?(table_name)
102
+ end
58
103
  end
59
104
  end
60
105
  end
@@ -2,6 +2,15 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Scoping
5
+ class DefaultScope # :nodoc:
6
+ attr_reader :scope, :all_queries
7
+
8
+ def initialize(scope, all_queries = nil)
9
+ @scope = scope
10
+ @all_queries = all_queries
11
+ end
12
+ end
13
+
5
14
  module Default
6
15
  extend ActiveSupport::Concern
7
16
 
@@ -15,14 +24,22 @@ module ActiveRecord
15
24
  # Returns a scope for the model without the previously set scopes.
16
25
  #
17
26
  # class Post < ActiveRecord::Base
27
+ # belongs_to :user
28
+ #
18
29
  # def self.default_scope
19
30
  # where(published: true)
20
31
  # end
21
32
  # end
22
33
  #
34
+ # class User < ActiveRecord::Base
35
+ # has_many :posts
36
+ # end
37
+ #
23
38
  # Post.all # Fires "SELECT * FROM posts WHERE published = true"
24
39
  # Post.unscoped.all # Fires "SELECT * FROM posts"
25
40
  # Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
41
+ # User.find(1).posts # Fires "SELECT * FROM posts WHERE published = true AND posts.user_id = 1"
42
+ # User.find(1).posts.unscoped # Fires "SELECT * FROM posts"
26
43
  #
27
44
  # This method also accepts a block. All queries inside the block will
28
45
  # not use the previously set scopes.
@@ -30,8 +47,8 @@ module ActiveRecord
30
47
  # Post.unscoped {
31
48
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
49
  # }
33
- def unscoped
34
- block_given? ? relation.scoping { yield } : relation
50
+ def unscoped(&block)
51
+ block_given? ? relation.scoping(&block) : relation
35
52
  end
36
53
 
37
54
  # Are there attributes associated with this scope?
@@ -39,12 +56,18 @@ module ActiveRecord
39
56
  super || default_scopes.any? || respond_to?(:default_scope)
40
57
  end
41
58
 
42
- def before_remove_const #:nodoc:
43
- self.current_scope = nil
59
+ # Checks if the model has any default scopes. If all_queries
60
+ # is set to true, the method will check if there are any
61
+ # default_scopes for the model where +all_queries+ is true.
62
+ def default_scopes?(all_queries: false)
63
+ if all_queries
64
+ self.default_scopes.any?(&:all_queries)
65
+ else
66
+ self.default_scopes.any?
67
+ end
44
68
  end
45
69
 
46
70
  private
47
-
48
71
  # Use this macro in your model to set a default scope for all operations on
49
72
  # the model.
50
73
  #
@@ -52,14 +75,30 @@ module ActiveRecord
52
75
  # default_scope { where(published: true) }
53
76
  # end
54
77
  #
55
- # Article.all # => SELECT * FROM articles WHERE published = true
78
+ # Article.all
79
+ # # SELECT * FROM articles WHERE published = true
56
80
  #
57
81
  # The #default_scope is also applied while creating/building a record.
58
- # It is not applied while updating a record.
82
+ # It is not applied while updating or deleting a record.
59
83
  #
60
84
  # Article.new.published # => true
61
85
  # Article.create.published # => true
62
86
  #
87
+ # To apply a #default_scope when updating or deleting a record, add
88
+ # <tt>all_queries: true</tt>:
89
+ #
90
+ # class Article < ActiveRecord::Base
91
+ # default_scope -> { where(blog_id: 1) }, all_queries: true
92
+ # end
93
+ #
94
+ # Applying a default scope to all queries will ensure that records
95
+ # are always queried by the additional conditions. Note that only
96
+ # where clauses apply, as it does not make sense to add order to
97
+ # queries that return a single object by primary key.
98
+ #
99
+ # Article.find(1).destroy
100
+ # # DELETE ... FROM `articles` where ID = 1 AND blog_id = 1;
101
+ #
63
102
  # (You can also pass any object which responds to +call+ to the
64
103
  # +default_scope+ macro, and it will be called when building the
65
104
  # default scope.)
@@ -72,7 +111,8 @@ module ActiveRecord
72
111
  # default_scope { where(rating: 'G') }
73
112
  # end
74
113
  #
75
- # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
114
+ # Article.all
115
+ # # SELECT * FROM articles WHERE published = true AND rating = 'G'
76
116
  #
77
117
  # This is also the case with inheritance and module includes where the
78
118
  # parent or module defines a #default_scope and the child or including
@@ -86,7 +126,7 @@ module ActiveRecord
86
126
  # # Should return a scope, you can call 'super' here etc.
87
127
  # end
88
128
  # end
89
- def default_scope(scope = nil, &block) # :doc:
129
+ def default_scope(scope = nil, all_queries: nil, &block) # :doc:
90
130
  scope = block if block_given?
91
131
 
92
132
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
@@ -97,10 +137,12 @@ module ActiveRecord
97
137
  "self.default_scope.)"
98
138
  end
99
139
 
100
- self.default_scopes += [scope]
140
+ default_scope = DefaultScope.new(scope, all_queries)
141
+
142
+ self.default_scopes += [default_scope]
101
143
  end
102
144
 
103
- def build_default_scope(relation = relation())
145
+ def build_default_scope(relation = relation(), all_queries: nil)
104
146
  return if abstract_class?
105
147
 
106
148
  if default_scope_override.nil?
@@ -110,26 +152,38 @@ module ActiveRecord
110
152
  if default_scope_override
111
153
  # The user has defined their own default scope method, so call that
112
154
  evaluate_default_scope do
113
- if scope = default_scope
114
- relation.merge!(scope)
115
- end
155
+ relation.scoping { default_scope }
116
156
  end
117
157
  elsif default_scopes.any?
118
158
  evaluate_default_scope do
119
- default_scopes.inject(relation) do |default_scope, scope|
120
- scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
121
- default_scope.instance_exec(&scope) || default_scope
159
+ default_scopes.inject(relation) do |combined_scope, scope_obj|
160
+ if execute_scope?(all_queries, scope_obj)
161
+ scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
162
+
163
+ combined_scope.instance_exec(&scope) || combined_scope
164
+ else
165
+ combined_scope
166
+ end
122
167
  end
123
168
  end
124
169
  end
125
170
  end
126
171
 
172
+ # If all_queries is nil, only execute on select and insert queries.
173
+ #
174
+ # If all_queries is true, check if the default_scope object has
175
+ # all_queries set, then execute on all queries; select, insert, update,
176
+ # delete, and reload.
177
+ def execute_scope?(all_queries, default_scope_obj)
178
+ all_queries.nil? || all_queries && default_scope_obj.all_queries
179
+ end
180
+
127
181
  def ignore_default_scope?
128
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
182
+ ScopeRegistry.ignore_default_scope(base_class)
129
183
  end
130
184
 
131
185
  def ignore_default_scope=(ignore)
132
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
186
+ ScopeRegistry.set_ignore_default_scope(base_class, ignore)
133
187
  end
134
188
 
135
189
  # The ignore_default_scope flag is used to prevent an infinite recursion