activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -10,6 +10,7 @@ module ActiveRecord
10
10
  included do
11
11
  class_attribute :_reflections, instance_writer: false, default: {}
12
12
  class_attribute :aggregate_reflections, instance_writer: false, default: {}
13
+ class_attribute :automatic_scope_inversing, instance_writer: false, default: false
13
14
  end
14
15
 
15
16
  class << self
@@ -45,6 +46,8 @@ module ActiveRecord
45
46
  end
46
47
  end
47
48
 
49
+ # = Active Record Reflection
50
+ #
48
51
  # \Reflection enables the ability to examine the associations and aggregations of
49
52
  # Active Record classes and objects. This information, for example,
50
53
  # can be used in a form builder that takes an Active Record object
@@ -115,7 +118,7 @@ module ActiveRecord
115
118
  reflections[association.to_s]
116
119
  end
117
120
 
118
- def _reflect_on_association(association) #:nodoc:
121
+ def _reflect_on_association(association) # :nodoc:
119
122
  _reflections[association.to_s]
120
123
  end
121
124
 
@@ -127,6 +130,14 @@ module ActiveRecord
127
130
  def clear_reflections_cache # :nodoc:
128
131
  @__reflections = nil
129
132
  end
133
+
134
+ private
135
+ def inherited(subclass)
136
+ super
137
+ subclass.class_eval do
138
+ @__reflections = nil
139
+ end
140
+ end
130
141
  end
131
142
 
132
143
  # Holds all the methods that are shared between MacroReflection and ThroughReflection.
@@ -143,6 +154,14 @@ module ActiveRecord
143
154
  # PolymorphicReflection
144
155
  # RuntimeReflection
145
156
  class AbstractReflection # :nodoc:
157
+ def initialize
158
+ @class_name = nil
159
+ @counter_cache_column = nil
160
+ @inverse_of = nil
161
+ @inverse_which_updates_counter_cache_defined = false
162
+ @inverse_which_updates_counter_cache = nil
163
+ end
164
+
146
165
  def through_reflection?
147
166
  false
148
167
  end
@@ -182,10 +201,14 @@ module ActiveRecord
182
201
 
183
202
  scope_chain_items.inject(klass_scope, &:merge!)
184
203
 
185
- primary_key = join_primary_key
186
- foreign_key = join_foreign_key
204
+ primary_key_column_names = Array(join_primary_key)
205
+ foreign_key_column_names = Array(join_foreign_key)
187
206
 
188
- klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
207
+ primary_foreign_key_pairs = primary_key_column_names.zip(foreign_key_column_names)
208
+
209
+ primary_foreign_key_pairs.each do |primary_key_column_name, foreign_key_column_name|
210
+ klass_scope.where!(table[primary_key_column_name].eq(foreign_table[foreign_key_column_name]))
211
+ end
189
212
 
190
213
  if klass.finder_needs_type_condition?
191
214
  klass_scope.where!(klass.send(:type_condition, table))
@@ -194,9 +217,9 @@ module ActiveRecord
194
217
  klass_scope
195
218
  end
196
219
 
197
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
220
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
198
221
  if scope
199
- [scope_for(build_scope(table, predicate_builder, klass))]
222
+ [scope_for(build_scope(table, predicate_builder, klass), record)]
200
223
  else
201
224
  []
202
225
  end
@@ -230,14 +253,17 @@ module ActiveRecord
230
253
  end
231
254
 
232
255
  def check_validity_of_inverse!
233
- unless polymorphic?
234
- if has_inverse? && inverse_of.nil?
256
+ if !polymorphic? && has_inverse?
257
+ if inverse_of.nil?
235
258
  raise InverseOfAssociationNotFoundError.new(self)
236
259
  end
260
+ if inverse_of == self
261
+ raise InverseOfAssociationRecursiveError.new(self)
262
+ end
237
263
  end
238
264
  end
239
265
 
240
- # This shit is nasty. We need to avoid the following situation:
266
+ # We need to avoid the following situation:
241
267
  #
242
268
  # * An associated record is deleted via record.destroy
243
269
  # * Hence the callbacks run, and they find a belongs_to on the record with a
@@ -248,10 +274,16 @@ module ActiveRecord
248
274
  #
249
275
  # Hence this method.
250
276
  def inverse_which_updates_counter_cache
251
- return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
252
- @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
253
- inverse.counter_cache_column == counter_cache_column
277
+ unless @inverse_which_updates_counter_cache_defined
278
+ if counter_cache_column
279
+ inverse_candidates = inverse_of ? [inverse_of] : klass.reflect_on_all_associations(:belongs_to)
280
+ @inverse_which_updates_counter_cache = inverse_candidates.find do |inverse|
281
+ inverse.counter_cache_column == counter_cache_column && (inverse.polymorphic? || inverse.klass == active_record)
282
+ end
283
+ end
284
+ @inverse_which_updates_counter_cache_defined = true
254
285
  end
286
+ @inverse_which_updates_counter_cache
255
287
  end
256
288
  alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
257
289
 
@@ -293,6 +325,12 @@ module ActiveRecord
293
325
  options[:strict_loading]
294
326
  end
295
327
 
328
+ def strict_loading_violation_message(owner)
329
+ message = +"`#{owner}` is marked for strict_loading."
330
+ message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}"
331
+ message << " named `:#{name}` cannot be lazily loaded."
332
+ end
333
+
296
334
  protected
297
335
  def actual_source_reflection # FIXME: this is a horrible name
298
336
  self
@@ -306,6 +344,12 @@ module ActiveRecord
306
344
  def primary_key(klass)
307
345
  klass.primary_key || raise(UnknownPrimaryKey.new(klass))
308
346
  end
347
+
348
+ def ensure_option_not_given_as_class!(option_name)
349
+ if options[option_name] && options[option_name].class == Class
350
+ raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string."
351
+ end
352
+ end
309
353
  end
310
354
 
311
355
  # Base class for AggregateReflection and AssociationReflection. Objects of
@@ -330,6 +374,7 @@ module ActiveRecord
330
374
  attr_reader :plural_name # :nodoc:
331
375
 
332
376
  def initialize(name, scope, options, active_record)
377
+ super()
333
378
  @name = name
334
379
  @scope = scope
335
380
  @options = options
@@ -337,6 +382,7 @@ module ActiveRecord
337
382
  @klass = options[:anonymous_class]
338
383
  @plural_name = active_record.pluralize_table_names ?
339
384
  name.to_s.pluralize : name.to_s
385
+ validate_reflection!
340
386
  end
341
387
 
342
388
  def autosave=(autosave)
@@ -388,11 +434,22 @@ module ActiveRecord
388
434
  def derive_class_name
389
435
  name.to_s.camelize
390
436
  end
437
+
438
+ def validate_reflection!
439
+ return unless options[:foreign_key].is_a?(Array)
440
+
441
+ message = <<~MSG.squish
442
+ Passing #{options[:foreign_key]} array to :foreign_key option
443
+ on the #{active_record}##{name} association is not supported.
444
+ Use the query_constraints: #{options[:foreign_key]} option instead to represent a composite foreign key.
445
+ MSG
446
+ raise ArgumentError, message
447
+ end
391
448
  end
392
449
 
393
450
  # Holds all the metadata about an aggregation as it was specified in the
394
451
  # Active Record class.
395
- class AggregateReflection < MacroReflection #:nodoc:
452
+ class AggregateReflection < MacroReflection # :nodoc:
396
453
  def mapping
397
454
  mapping = options[:mapping] || [name, name]
398
455
  mapping.first.is_a?(Array) ? mapping : [mapping]
@@ -401,12 +458,29 @@ module ActiveRecord
401
458
 
402
459
  # Holds all the metadata about an association as it was specified in the
403
460
  # Active Record class.
404
- class AssociationReflection < MacroReflection #:nodoc:
461
+ class AssociationReflection < MacroReflection # :nodoc:
405
462
  def compute_class(name)
406
463
  if polymorphic?
407
464
  raise ArgumentError, "Polymorphic associations do not support computing the class."
408
465
  end
409
- active_record.send(:compute_type, name)
466
+
467
+ begin
468
+ klass = active_record.send(:compute_type, name)
469
+ rescue NameError => error
470
+ if error.name.match?(/(?:\A|::)#{name}\z/)
471
+ message = "Missing model class #{name} for the #{active_record}##{self.name} association."
472
+ message += " You can specify a different model class with the :class_name option." unless options[:class_name]
473
+ raise NameError.new(message, name)
474
+ else
475
+ raise
476
+ end
477
+ end
478
+
479
+ unless klass < ActiveRecord::Base
480
+ raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
481
+ end
482
+
483
+ klass
410
484
  end
411
485
 
412
486
  attr_reader :type, :foreign_type
@@ -416,11 +490,12 @@ module ActiveRecord
416
490
  super
417
491
  @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
492
  @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
419
- @constructable = calculate_constructable(macro, options)
493
+ @join_table = nil
494
+ @foreign_key = nil
495
+ @association_foreign_key = nil
496
+ @association_primary_key = nil
420
497
 
421
- if options[:class_name] && options[:class_name].class == Class
422
- raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
423
- end
498
+ ensure_option_not_given_as_class!(:class_name)
424
499
  end
425
500
 
426
501
  def association_scope_cache(klass, owner, &block)
@@ -431,16 +506,24 @@ module ActiveRecord
431
506
  klass.cached_find_by_statement(key, &block)
432
507
  end
433
508
 
434
- def constructable? # :nodoc:
435
- @constructable
436
- end
437
-
438
509
  def join_table
439
510
  @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
440
511
  end
441
512
 
442
- def foreign_key
443
- @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
513
+ def foreign_key(infer_from_inverse_of: true)
514
+ @foreign_key ||= if options[:query_constraints]
515
+ options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
516
+ elsif options[:foreign_key]
517
+ options[:foreign_key].to_s
518
+ else
519
+ derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
520
+
521
+ if active_record.has_query_constraints?
522
+ derived_fk = derive_fk_query_constraints(derived_fk)
523
+ end
524
+
525
+ derived_fk
526
+ end
444
527
  end
445
528
 
446
529
  def association_foreign_key
@@ -452,36 +535,62 @@ module ActiveRecord
452
535
  end
453
536
 
454
537
  def active_record_primary_key
455
- @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
538
+ custom_primary_key = options[:primary_key]
539
+ @active_record_primary_key ||= if custom_primary_key
540
+ if custom_primary_key.is_a?(Array)
541
+ custom_primary_key.map { |pk| pk.to_s.freeze }.freeze
542
+ else
543
+ custom_primary_key.to_s.freeze
544
+ end
545
+ elsif active_record.has_query_constraints? || options[:query_constraints]
546
+ active_record.query_constraints_list
547
+ elsif active_record.composite_primary_key?
548
+ # If active_record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
549
+ primary_key = primary_key(active_record)
550
+ primary_key.include?("id") ? "id" : primary_key.freeze
551
+ else
552
+ primary_key(active_record).freeze
553
+ end
456
554
  end
457
555
 
458
556
  def join_primary_key(klass = nil)
459
557
  foreign_key
460
558
  end
461
559
 
560
+ def join_primary_type
561
+ type
562
+ end
563
+
462
564
  def join_foreign_key
463
565
  active_record_primary_key
464
566
  end
465
567
 
466
568
  def check_validity!
467
569
  check_validity_of_inverse!
570
+
571
+ if !polymorphic? && (klass.composite_primary_key? || active_record.composite_primary_key?)
572
+ if (has_one? || collection?) && Array(active_record_primary_key).length != Array(foreign_key).length
573
+ raise CompositePrimaryKeyMismatchError.new(self)
574
+ elsif belongs_to? && Array(association_primary_key).length != Array(foreign_key).length
575
+ raise CompositePrimaryKeyMismatchError.new(self)
576
+ end
577
+ end
468
578
  end
469
579
 
470
- def check_preloadable!
580
+ def check_eager_loadable!
471
581
  return unless scope
472
582
 
473
583
  unless scope.arity == 0
474
584
  raise ArgumentError, <<-MSG.squish
475
585
  The association scope '#{name}' is instance dependent (the scope
476
- block takes an argument). Preloading instance dependent scopes is
477
- not supported.
586
+ block takes an argument). Eager loading instance dependent scopes
587
+ is not supported.
478
588
  MSG
479
589
  end
480
590
  end
481
- alias :check_eager_loadable! :check_preloadable!
482
591
 
483
592
  def join_id_for(owner) # :nodoc:
484
- owner[join_foreign_key]
593
+ Array(join_foreign_key).map { |key| owner._read_attribute(key) }
485
594
  end
486
595
 
487
596
  def through_reflection
@@ -563,8 +672,9 @@ module ActiveRecord
563
672
  options[:polymorphic]
564
673
  end
565
674
 
566
- VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
567
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
675
+ def polymorphic_name
676
+ active_record.polymorphic_name
677
+ end
568
678
 
569
679
  def add_as_source(seed)
570
680
  seed
@@ -583,10 +693,6 @@ module ActiveRecord
583
693
  end
584
694
 
585
695
  private
586
- def calculate_constructable(macro, options)
587
- true
588
- end
589
-
590
696
  # Attempts to find the inverse association name automatically.
591
697
  # If it cannot find a suitable inverse association name, it returns
592
698
  # +nil+.
@@ -605,7 +711,9 @@ module ActiveRecord
605
711
 
606
712
  begin
607
713
  reflection = klass._reflect_on_association(inverse_name)
608
- rescue NameError
714
+ rescue NameError => error
715
+ raise unless error.name.to_s == class_name
716
+
609
717
  # Give up: we couldn't compute the klass type so we won't be able
610
718
  # to find any associations either.
611
719
  reflection = false
@@ -623,9 +731,10 @@ module ActiveRecord
623
731
  # with the current reflection's klass name.
624
732
  def valid_inverse_reflection?(reflection)
625
733
  reflection &&
734
+ reflection != self &&
626
735
  foreign_key == reflection.foreign_key &&
627
736
  klass <= reflection.active_record &&
628
- can_find_inverse_of_automatically?(reflection)
737
+ can_find_inverse_of_automatically?(reflection, true)
629
738
  end
630
739
 
631
740
  # Checks to see if the reflection doesn't have any options that prevent
@@ -634,14 +743,25 @@ module ActiveRecord
634
743
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
635
744
  # Third, we must not have options such as <tt>:foreign_key</tt>
636
745
  # which prevent us from correctly guessing the inverse association.
637
- #
638
- # Anything with a scope can additionally ruin our attempt at finding an
639
- # inverse, so we exclude reflections with scopes.
640
- def can_find_inverse_of_automatically?(reflection)
746
+ def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
641
747
  reflection.options[:inverse_of] != false &&
642
- VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) &&
643
- !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] } &&
748
+ !reflection.options[:through] &&
749
+ !reflection.options[:foreign_key] &&
750
+ scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
751
+ end
752
+
753
+ # Scopes on the potential inverse reflection prevent automatic
754
+ # <tt>inverse_of</tt>, since the scope could exclude the owner record
755
+ # we would inverse from. Scopes on the reflection itself allow for
756
+ # automatic <tt>inverse_of</tt> as long as
757
+ # <tt>config.active_record.automatic_scope_inversing<tt> is set to
758
+ # +true+ (the default for new applications).
759
+ def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
760
+ if inverse_reflection
644
761
  !reflection.scope
762
+ else
763
+ !reflection.scope || reflection.klass.automatic_scope_inversing
764
+ end
645
765
  end
646
766
 
647
767
  def derive_class_name
@@ -650,13 +770,55 @@ module ActiveRecord
650
770
  class_name.camelize
651
771
  end
652
772
 
653
- def derive_foreign_key
773
+ def derive_foreign_key(infer_from_inverse_of: true)
654
774
  if belongs_to?
655
775
  "#{name}_id"
656
776
  elsif options[:as]
657
777
  "#{options[:as]}_id"
778
+ elsif options[:inverse_of] && infer_from_inverse_of
779
+ inverse_of.foreign_key(infer_from_inverse_of: false)
658
780
  else
659
- active_record.name.foreign_key
781
+ active_record.model_name.to_s.foreign_key
782
+ end
783
+ end
784
+
785
+ def derive_fk_query_constraints(foreign_key)
786
+ primary_query_constraints = active_record.query_constraints_list
787
+ owner_pk = active_record.primary_key
788
+
789
+ if primary_query_constraints.size > 2
790
+ raise ArgumentError, <<~MSG.squish
791
+ The query constraints list on the `#{active_record}` model has more than 2
792
+ attributes. Active Record is unable to derive the query constraints
793
+ for the association. You need to explicitly define the query constraints
794
+ for this association.
795
+ MSG
796
+ end
797
+
798
+ if !primary_query_constraints.include?(owner_pk)
799
+ raise ArgumentError, <<~MSG.squish
800
+ The query constraints on the `#{active_record}` model does not include the primary
801
+ key so Active Record is unable to derive the foreign key constraints for
802
+ the association. You need to explicitly define the query constraints for this
803
+ association.
804
+ MSG
805
+ end
806
+
807
+ return foreign_key if primary_query_constraints.include?(foreign_key)
808
+
809
+ first_key, last_key = primary_query_constraints
810
+
811
+ if first_key == owner_pk
812
+ [foreign_key, last_key.to_s]
813
+ elsif last_key == owner_pk
814
+ [first_key.to_s, foreign_key]
815
+ else
816
+ raise ArgumentError, <<~MSG.squish
817
+ Active Record couldn't correctly interpret the query constraints
818
+ for the `#{active_record}` model. The query constraints on `#{active_record}` are
819
+ `#{primary_query_constraints}` and the foreign key is `#{foreign_key}`.
820
+ You need to explicitly set the query constraints for this association.
821
+ MSG
660
822
  end
661
823
  end
662
824
 
@@ -691,11 +853,6 @@ module ActiveRecord
691
853
  Associations::HasOneAssociation
692
854
  end
693
855
  end
694
-
695
- private
696
- def calculate_constructable(macro, options)
697
- !options[:through]
698
- end
699
856
  end
700
857
 
701
858
  class BelongsToReflection < AssociationReflection # :nodoc:
@@ -714,7 +871,17 @@ module ActiveRecord
714
871
  # klass option is necessary to support loading polymorphic associations
715
872
  def association_primary_key(klass = nil)
716
873
  if primary_key = options[:primary_key]
717
- @association_primary_key ||= -primary_key.to_s
874
+ @association_primary_key ||= if primary_key.is_a?(Array)
875
+ primary_key.map { |pk| pk.to_s.freeze }.freeze
876
+ else
877
+ -primary_key.to_s
878
+ end
879
+ elsif (klass || self.klass).has_query_constraints? || options[:query_constraints]
880
+ (klass || self.klass).composite_query_constraints_list
881
+ elsif (klass || self.klass).composite_primary_key?
882
+ # If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
883
+ primary_key = (klass || self.klass).primary_key
884
+ primary_key.include?("id") ? "id" : primary_key
718
885
  else
719
886
  primary_key(klass || self.klass)
720
887
  end
@@ -733,13 +900,9 @@ module ActiveRecord
733
900
  end
734
901
 
735
902
  private
736
- def can_find_inverse_of_automatically?(_)
903
+ def can_find_inverse_of_automatically?(*)
737
904
  !polymorphic? && super
738
905
  end
739
-
740
- def calculate_constructable(macro, options)
741
- !polymorphic?
742
- end
743
906
  end
744
907
 
745
908
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -752,14 +915,17 @@ module ActiveRecord
752
915
 
753
916
  # Holds all the metadata about a :through association as it was specified
754
917
  # in the Active Record class.
755
- class ThroughReflection < AbstractReflection #:nodoc:
918
+ class ThroughReflection < AbstractReflection # :nodoc:
756
919
  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
920
  :active_record_primary_key, :join_foreign_key, to: :source_reflection
758
921
 
759
922
  def initialize(delegate_reflection)
923
+ super()
760
924
  @delegate_reflection = delegate_reflection
761
925
  @klass = delegate_reflection.options[:anonymous_class]
762
926
  @source_reflection_name = delegate_reflection.options[:source]
927
+
928
+ ensure_option_not_given_as_class!(:source_type)
763
929
  end
764
930
 
765
931
  def through_reflection?
@@ -840,8 +1006,8 @@ module ActiveRecord
840
1006
  source_reflection.scopes + super
841
1007
  end
842
1008
 
843
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
- source_reflection.join_scopes(table, predicate_builder, klass) + super
1009
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1010
+ source_reflection.join_scopes(table, predicate_builder, klass, record) + super
845
1011
  end
846
1012
 
847
1013
  def has_scope?
@@ -888,24 +1054,23 @@ module ActiveRecord
888
1054
  end
889
1055
 
890
1056
  def source_reflection_name # :nodoc:
891
- return @source_reflection_name if @source_reflection_name
892
-
893
- names = [name.to_s.singularize, name].collect(&:to_sym).uniq
894
- names = names.find_all { |n|
895
- through_reflection.klass._reflect_on_association(n)
896
- }
897
-
898
- if names.length > 1
899
- raise AmbiguousSourceReflectionForThroughAssociation.new(
900
- active_record.name,
901
- macro,
902
- name,
903
- options,
904
- source_reflection_names
905
- )
1057
+ @source_reflection_name ||= begin
1058
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
1059
+ names = names.find_all { |n|
1060
+ through_reflection.klass._reflect_on_association(n)
1061
+ }
1062
+
1063
+ if names.length > 1
1064
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
1065
+ active_record.name,
1066
+ macro,
1067
+ name,
1068
+ options,
1069
+ source_reflection_names
1070
+ )
1071
+ end
1072
+ names.first
906
1073
  end
907
-
908
- @source_reflection_name = names.first
909
1074
  end
910
1075
 
911
1076
  def source_options
@@ -1009,13 +1174,14 @@ module ActiveRecord
1009
1174
  :name, :scope_for, to: :@reflection
1010
1175
 
1011
1176
  def initialize(reflection, previous_reflection)
1177
+ super()
1012
1178
  @reflection = reflection
1013
1179
  @previous_reflection = previous_reflection
1014
1180
  end
1015
1181
 
1016
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1017
- scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1018
- scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1182
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1183
+ scopes = @previous_reflection.join_scopes(table, predicate_builder, klass, record) + super
1184
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
1019
1185
  end
1020
1186
 
1021
1187
  def constraints
@@ -1034,6 +1200,7 @@ module ActiveRecord
1034
1200
  delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1035
1201
 
1036
1202
  def initialize(reflection, association)
1203
+ super()
1037
1204
  @reflection = reflection
1038
1205
  @association = association
1039
1206
  end
@@ -5,11 +5,27 @@ module ActiveRecord
5
5
  class BatchEnumerator
6
6
  include Enumerable
7
7
 
8
- def initialize(of: 1000, start: nil, finish: nil, relation:) #:nodoc:
8
+ def initialize(of: 1000, start: nil, finish: nil, relation:, order: :asc, use_ranges: nil) # :nodoc:
9
9
  @of = of
10
10
  @relation = relation
11
11
  @start = start
12
12
  @finish = finish
13
+ @order = order
14
+ @use_ranges = use_ranges
15
+ end
16
+
17
+ # The primary key value from which the BatchEnumerator starts, inclusive of the value.
18
+ attr_reader :start
19
+
20
+ # The primary key value at which the BatchEnumerator ends, inclusive of the value.
21
+ attr_reader :finish
22
+
23
+ # The relation from which the BatchEnumerator yields batches.
24
+ attr_reader :relation
25
+
26
+ # The size of the batches yielded by the BatchEnumerator.
27
+ def batch_size
28
+ @of
13
29
  end
14
30
 
15
31
  # Looping through a collection of records from the database (using the
@@ -33,11 +49,11 @@ module ActiveRecord
33
49
  # Person.in_batches.each_record.with_index do |person, index|
34
50
  # person.award_trophy(index + 1)
35
51
  # end
36
- def each_record
52
+ def each_record(&block)
37
53
  return to_enum(:each_record) unless block_given?
38
54
 
39
- @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
40
- relation.records.each { |record| yield record }
55
+ @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true, order: @order).each do |relation|
56
+ relation.records.each(&block)
41
57
  end
42
58
  end
43
59
 
@@ -75,9 +91,9 @@ module ActiveRecord
75
91
  # Person.in_batches.each do |relation|
76
92
  # relation.update_all(awesome: true)
77
93
  # end
78
- def each
79
- enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
80
- return enum.each { |relation| yield relation } if block_given?
94
+ def each(&block)
95
+ enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false, order: @order, use_ranges: @use_ranges)
96
+ return enum.each(&block) if block_given?
81
97
  enum
82
98
  end
83
99
  end