activerecord 6.1.7 → 7.1.0

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 (307) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1516 -1019
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +17 -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 +50 -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 +35 -31
  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.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +423 -289
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +61 -14
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -46
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
  98. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  99. data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
  100. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  101. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  102. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
  103. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  104. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  107. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  108. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  109. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  110. data/lib/active_record/connection_adapters.rb +9 -6
  111. data/lib/active_record/connection_handling.rb +107 -136
  112. data/lib/active_record/core.rb +194 -224
  113. data/lib/active_record/counter_cache.rb +46 -25
  114. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  115. data/lib/active_record/database_configurations/database_config.rb +21 -12
  116. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  117. data/lib/active_record/database_configurations/url_config.rb +18 -12
  118. data/lib/active_record/database_configurations.rb +95 -59
  119. data/lib/active_record/delegated_type.rb +61 -15
  120. data/lib/active_record/deprecator.rb +7 -0
  121. data/lib/active_record/destroy_association_async_job.rb +3 -1
  122. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  123. data/lib/active_record/dynamic_matchers.rb +1 -1
  124. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  125. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  126. data/lib/active_record/encryption/cipher.rb +53 -0
  127. data/lib/active_record/encryption/config.rb +68 -0
  128. data/lib/active_record/encryption/configurable.rb +60 -0
  129. data/lib/active_record/encryption/context.rb +42 -0
  130. data/lib/active_record/encryption/contexts.rb +76 -0
  131. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  132. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  133. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  134. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  135. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  136. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  137. data/lib/active_record/encryption/encryptor.rb +155 -0
  138. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  139. data/lib/active_record/encryption/errors.rb +15 -0
  140. data/lib/active_record/encryption/extended_deterministic_queries.rb +172 -0
  141. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  142. data/lib/active_record/encryption/key.rb +28 -0
  143. data/lib/active_record/encryption/key_generator.rb +53 -0
  144. data/lib/active_record/encryption/key_provider.rb +46 -0
  145. data/lib/active_record/encryption/message.rb +33 -0
  146. data/lib/active_record/encryption/message_serializer.rb +92 -0
  147. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  148. data/lib/active_record/encryption/properties.rb +76 -0
  149. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  150. data/lib/active_record/encryption/scheme.rb +96 -0
  151. data/lib/active_record/encryption.rb +56 -0
  152. data/lib/active_record/enum.rb +156 -62
  153. data/lib/active_record/errors.rb +171 -15
  154. data/lib/active_record/explain.rb +23 -3
  155. data/lib/active_record/explain_registry.rb +11 -6
  156. data/lib/active_record/explain_subscriber.rb +1 -1
  157. data/lib/active_record/fixture_set/file.rb +15 -1
  158. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  159. data/lib/active_record/fixture_set/render_context.rb +2 -0
  160. data/lib/active_record/fixture_set/table_row.rb +70 -14
  161. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  162. data/lib/active_record/fixtures.rb +131 -86
  163. data/lib/active_record/future_result.rb +164 -0
  164. data/lib/active_record/gem_version.rb +3 -3
  165. data/lib/active_record/inheritance.rb +81 -29
  166. data/lib/active_record/insert_all.rb +133 -20
  167. data/lib/active_record/integration.rb +11 -10
  168. data/lib/active_record/internal_metadata.rb +117 -33
  169. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  170. data/lib/active_record/locking/optimistic.rb +36 -21
  171. data/lib/active_record/locking/pessimistic.rb +15 -6
  172. data/lib/active_record/log_subscriber.rb +52 -19
  173. data/lib/active_record/marshalling.rb +56 -0
  174. data/lib/active_record/message_pack.rb +124 -0
  175. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  176. data/lib/active_record/middleware/database_selector.rb +23 -13
  177. data/lib/active_record/middleware/shard_selector.rb +62 -0
  178. data/lib/active_record/migration/command_recorder.rb +108 -13
  179. data/lib/active_record/migration/compatibility.rb +221 -48
  180. data/lib/active_record/migration/default_strategy.rb +23 -0
  181. data/lib/active_record/migration/execution_strategy.rb +19 -0
  182. data/lib/active_record/migration/join_table.rb +1 -1
  183. data/lib/active_record/migration.rb +355 -171
  184. data/lib/active_record/model_schema.rb +116 -97
  185. data/lib/active_record/nested_attributes.rb +36 -15
  186. data/lib/active_record/no_touching.rb +3 -3
  187. data/lib/active_record/normalization.rb +159 -0
  188. data/lib/active_record/persistence.rb +405 -85
  189. data/lib/active_record/promise.rb +84 -0
  190. data/lib/active_record/query_cache.rb +3 -21
  191. data/lib/active_record/query_logs.rb +174 -0
  192. data/lib/active_record/query_logs_formatter.rb +41 -0
  193. data/lib/active_record/querying.rb +29 -6
  194. data/lib/active_record/railtie.rb +219 -43
  195. data/lib/active_record/railties/controller_runtime.rb +13 -9
  196. data/lib/active_record/railties/databases.rake +185 -249
  197. data/lib/active_record/railties/job_runtime.rb +23 -0
  198. data/lib/active_record/readonly_attributes.rb +41 -3
  199. data/lib/active_record/reflection.rb +229 -80
  200. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  201. data/lib/active_record/relation/batches.rb +192 -63
  202. data/lib/active_record/relation/calculations.rb +211 -90
  203. data/lib/active_record/relation/delegation.rb +27 -13
  204. data/lib/active_record/relation/finder_methods.rb +108 -51
  205. data/lib/active_record/relation/merger.rb +22 -13
  206. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  207. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  208. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  209. data/lib/active_record/relation/predicate_builder.rb +27 -20
  210. data/lib/active_record/relation/query_attribute.rb +30 -12
  211. data/lib/active_record/relation/query_methods.rb +654 -127
  212. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  213. data/lib/active_record/relation/spawn_methods.rb +20 -3
  214. data/lib/active_record/relation/where_clause.rb +10 -19
  215. data/lib/active_record/relation.rb +262 -120
  216. data/lib/active_record/result.rb +37 -11
  217. data/lib/active_record/runtime_registry.rb +18 -13
  218. data/lib/active_record/sanitization.rb +65 -20
  219. data/lib/active_record/schema.rb +36 -22
  220. data/lib/active_record/schema_dumper.rb +73 -24
  221. data/lib/active_record/schema_migration.rb +68 -33
  222. data/lib/active_record/scoping/default.rb +72 -15
  223. data/lib/active_record/scoping/named.rb +5 -13
  224. data/lib/active_record/scoping.rb +65 -34
  225. data/lib/active_record/secure_password.rb +60 -0
  226. data/lib/active_record/secure_token.rb +21 -3
  227. data/lib/active_record/serialization.rb +6 -1
  228. data/lib/active_record/signed_id.rb +10 -8
  229. data/lib/active_record/store.rb +10 -10
  230. data/lib/active_record/suppressor.rb +13 -15
  231. data/lib/active_record/table_metadata.rb +16 -3
  232. data/lib/active_record/tasks/database_tasks.rb +225 -136
  233. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  234. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  235. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  236. data/lib/active_record/test_databases.rb +1 -1
  237. data/lib/active_record/test_fixtures.rb +116 -96
  238. data/lib/active_record/timestamp.rb +28 -17
  239. data/lib/active_record/token_for.rb +113 -0
  240. data/lib/active_record/touch_later.rb +11 -6
  241. data/lib/active_record/transactions.rb +48 -27
  242. data/lib/active_record/translation.rb +3 -3
  243. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  244. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  245. data/lib/active_record/type/internal/timezone.rb +7 -2
  246. data/lib/active_record/type/serialized.rb +9 -5
  247. data/lib/active_record/type/time.rb +4 -0
  248. data/lib/active_record/type/type_map.rb +17 -20
  249. data/lib/active_record/type.rb +1 -2
  250. data/lib/active_record/validations/absence.rb +1 -1
  251. data/lib/active_record/validations/associated.rb +4 -4
  252. data/lib/active_record/validations/numericality.rb +5 -4
  253. data/lib/active_record/validations/presence.rb +5 -28
  254. data/lib/active_record/validations/uniqueness.rb +51 -6
  255. data/lib/active_record/validations.rb +8 -4
  256. data/lib/active_record/version.rb +1 -1
  257. data/lib/active_record.rb +335 -32
  258. data/lib/arel/attributes/attribute.rb +0 -8
  259. data/lib/arel/crud.rb +28 -22
  260. data/lib/arel/delete_manager.rb +18 -4
  261. data/lib/arel/errors.rb +10 -0
  262. data/lib/arel/factory_methods.rb +4 -0
  263. data/lib/arel/filter_predications.rb +9 -0
  264. data/lib/arel/insert_manager.rb +2 -3
  265. data/lib/arel/nodes/and.rb +4 -0
  266. data/lib/arel/nodes/binary.rb +6 -1
  267. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  268. data/lib/arel/nodes/casted.rb +1 -1
  269. data/lib/arel/nodes/cte.rb +36 -0
  270. data/lib/arel/nodes/delete_statement.rb +12 -13
  271. data/lib/arel/nodes/filter.rb +10 -0
  272. data/lib/arel/nodes/fragments.rb +35 -0
  273. data/lib/arel/nodes/function.rb +1 -0
  274. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  275. data/lib/arel/nodes/insert_statement.rb +2 -2
  276. data/lib/arel/nodes/leading_join.rb +8 -0
  277. data/lib/arel/nodes/node.rb +111 -2
  278. data/lib/arel/nodes/select_core.rb +2 -2
  279. data/lib/arel/nodes/select_statement.rb +2 -2
  280. data/lib/arel/nodes/sql_literal.rb +6 -0
  281. data/lib/arel/nodes/table_alias.rb +4 -0
  282. data/lib/arel/nodes/update_statement.rb +8 -3
  283. data/lib/arel/nodes.rb +5 -0
  284. data/lib/arel/predications.rb +13 -3
  285. data/lib/arel/select_manager.rb +10 -4
  286. data/lib/arel/table.rb +9 -6
  287. data/lib/arel/tree_manager.rb +0 -12
  288. data/lib/arel/update_manager.rb +18 -4
  289. data/lib/arel/visitors/dot.rb +80 -90
  290. data/lib/arel/visitors/mysql.rb +16 -3
  291. data/lib/arel/visitors/postgresql.rb +0 -10
  292. data/lib/arel/visitors/to_sql.rb +139 -19
  293. data/lib/arel/visitors/visitor.rb +2 -2
  294. data/lib/arel.rb +18 -3
  295. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  296. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  297. data/lib/rails/generators/active_record/migration.rb +3 -1
  298. data/lib/rails/generators/active_record/model/USAGE +113 -0
  299. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  300. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  302. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  303. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  304. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  305. metadata +92 -13
  306. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  307. data/lib/active_record/null_relation.rb +0 -67
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/runtime_registry"
4
+
5
+ module ActiveRecord
6
+ module Railties # :nodoc:
7
+ module JobRuntime # :nodoc:
8
+ private
9
+ def instrument(operation, payload = {}, &block)
10
+ if operation == :perform && block
11
+ super(operation, payload) do
12
+ db_runtime_before_perform = ActiveRecord::RuntimeRegistry.sql_runtime
13
+ result = block.call
14
+ payload[:db_runtime] = ActiveRecord::RuntimeRegistry.sql_runtime - db_runtime_before_perform
15
+ result
16
+ end
17
+ else
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
+ class ReadonlyAttributeError < ActiveRecordError
5
+ end
6
+
4
7
  module ReadonlyAttributes
5
8
  extend ActiveSupport::Concern
6
9
 
@@ -9,10 +12,27 @@ module ActiveRecord
9
12
  end
10
13
 
11
14
  module ClassMethods
12
- # Attributes listed as readonly will be used to create a new record but update operations will
13
- # ignore these fields.
15
+ # Attributes listed as readonly will be used to create a new record.
16
+ # Assigning a new value to a readonly attribute on a persisted record raises an error.
17
+ #
18
+ # By setting +config.active_record.raise_on_assign_to_attr_readonly+ to +false+, it will
19
+ # not raise. The value will change in memory, but will not be persisted on +save+.
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # class Post < ActiveRecord::Base
24
+ # attr_readonly :title
25
+ # end
26
+ #
27
+ # post = Post.create!(title: "Introducing Ruby on Rails!")
28
+ # post.title = "a different title" # raises ActiveRecord::ReadonlyAttributeError
29
+ # post.update(title: "a different title") # raises ActiveRecord::ReadonlyAttributeError
14
30
  def attr_readonly(*attributes)
15
- self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
31
+ self._attr_readonly |= attributes.map(&:to_s)
32
+
33
+ if ActiveRecord.raise_on_assign_to_attr_readonly
34
+ include(HasReadonlyAttributes)
35
+ end
16
36
  end
17
37
 
18
38
  # Returns an array of all the attributes that have been specified as readonly.
@@ -24,5 +44,23 @@ module ActiveRecord
24
44
  _attr_readonly.include?(name)
25
45
  end
26
46
  end
47
+
48
+ module HasReadonlyAttributes # :nodoc:
49
+ def write_attribute(attr_name, value)
50
+ if !new_record? && self.class.readonly_attribute?(attr_name.to_s)
51
+ raise ReadonlyAttributeError.new(attr_name)
52
+ end
53
+
54
+ super
55
+ end
56
+
57
+ def _write_attribute(attr_name, value)
58
+ if !new_record? && self.class.readonly_attribute?(attr_name.to_s)
59
+ raise ReadonlyAttributeError.new(attr_name)
60
+ end
61
+
62
+ super
63
+ end
64
+ end
27
65
  end
28
66
  end
@@ -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
@@ -392,7 +437,7 @@ module ActiveRecord
392
437
 
393
438
  # Holds all the metadata about an aggregation as it was specified in the
394
439
  # Active Record class.
395
- class AggregateReflection < MacroReflection #:nodoc:
440
+ class AggregateReflection < MacroReflection # :nodoc:
396
441
  def mapping
397
442
  mapping = options[:mapping] || [name, name]
398
443
  mapping.first.is_a?(Array) ? mapping : [mapping]
@@ -401,12 +446,29 @@ module ActiveRecord
401
446
 
402
447
  # Holds all the metadata about an association as it was specified in the
403
448
  # Active Record class.
404
- class AssociationReflection < MacroReflection #:nodoc:
449
+ class AssociationReflection < MacroReflection # :nodoc:
405
450
  def compute_class(name)
406
451
  if polymorphic?
407
452
  raise ArgumentError, "Polymorphic associations do not support computing the class."
408
453
  end
409
- active_record.send(:compute_type, name)
454
+
455
+ begin
456
+ klass = active_record.send(:compute_type, name)
457
+ rescue NameError => error
458
+ if error.name.match?(/(?:\A|::)#{name}\z/)
459
+ message = "Missing model class #{name} for the #{active_record}##{self.name} association."
460
+ message += " You can specify a different model class with the :class_name option." unless options[:class_name]
461
+ raise NameError.new(message, name)
462
+ else
463
+ raise
464
+ end
465
+ end
466
+
467
+ unless klass < ActiveRecord::Base
468
+ raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
469
+ end
470
+
471
+ klass
410
472
  end
411
473
 
412
474
  attr_reader :type, :foreign_type
@@ -416,11 +478,12 @@ module ActiveRecord
416
478
  super
417
479
  @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
480
  @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
419
- @constructable = calculate_constructable(macro, options)
481
+ @join_table = nil
482
+ @foreign_key = nil
483
+ @association_foreign_key = nil
484
+ @association_primary_key = nil
420
485
 
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
486
+ ensure_option_not_given_as_class!(:class_name)
424
487
  end
425
488
 
426
489
  def association_scope_cache(klass, owner, &block)
@@ -431,16 +494,24 @@ module ActiveRecord
431
494
  klass.cached_find_by_statement(key, &block)
432
495
  end
433
496
 
434
- def constructable? # :nodoc:
435
- @constructable
436
- end
437
-
438
497
  def join_table
439
498
  @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
440
499
  end
441
500
 
442
- def foreign_key
443
- @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
501
+ def foreign_key(infer_from_inverse_of: true)
502
+ @foreign_key ||= if options[:query_constraints]
503
+ options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
504
+ elsif options[:foreign_key]
505
+ options[:foreign_key].to_s
506
+ else
507
+ derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
508
+
509
+ if active_record.has_query_constraints?
510
+ derived_fk = derive_fk_query_constraints(derived_fk)
511
+ end
512
+
513
+ derived_fk
514
+ end
444
515
  end
445
516
 
446
517
  def association_foreign_key
@@ -452,36 +523,62 @@ module ActiveRecord
452
523
  end
453
524
 
454
525
  def active_record_primary_key
455
- @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
526
+ custom_primary_key = options[:primary_key]
527
+ @active_record_primary_key ||= if custom_primary_key
528
+ if custom_primary_key.is_a?(Array)
529
+ custom_primary_key.map { |pk| pk.to_s.freeze }.freeze
530
+ else
531
+ custom_primary_key.to_s.freeze
532
+ end
533
+ elsif active_record.has_query_constraints? || options[:query_constraints]
534
+ active_record.query_constraints_list
535
+ elsif active_record.composite_primary_key?
536
+ # If active_record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
537
+ primary_key = primary_key(active_record)
538
+ primary_key.include?("id") ? "id" : primary_key.freeze
539
+ else
540
+ primary_key(active_record).freeze
541
+ end
456
542
  end
457
543
 
458
544
  def join_primary_key(klass = nil)
459
545
  foreign_key
460
546
  end
461
547
 
548
+ def join_primary_type
549
+ type
550
+ end
551
+
462
552
  def join_foreign_key
463
553
  active_record_primary_key
464
554
  end
465
555
 
466
556
  def check_validity!
467
557
  check_validity_of_inverse!
558
+
559
+ if !polymorphic? && (klass.composite_primary_key? || active_record.composite_primary_key?)
560
+ if (has_one? || collection?) && Array(active_record_primary_key).length != Array(foreign_key).length
561
+ raise CompositePrimaryKeyMismatchError.new(self)
562
+ elsif belongs_to? && Array(association_primary_key).length != Array(foreign_key).length
563
+ raise CompositePrimaryKeyMismatchError.new(self)
564
+ end
565
+ end
468
566
  end
469
567
 
470
- def check_preloadable!
568
+ def check_eager_loadable!
471
569
  return unless scope
472
570
 
473
571
  unless scope.arity == 0
474
572
  raise ArgumentError, <<-MSG.squish
475
573
  The association scope '#{name}' is instance dependent (the scope
476
- block takes an argument). Preloading instance dependent scopes is
477
- not supported.
574
+ block takes an argument). Eager loading instance dependent scopes
575
+ is not supported.
478
576
  MSG
479
577
  end
480
578
  end
481
- alias :check_eager_loadable! :check_preloadable!
482
579
 
483
580
  def join_id_for(owner) # :nodoc:
484
- owner[join_foreign_key]
581
+ Array(join_foreign_key).map { |key| owner._read_attribute(key) }
485
582
  end
486
583
 
487
584
  def through_reflection
@@ -563,8 +660,9 @@ module ActiveRecord
563
660
  options[:polymorphic]
564
661
  end
565
662
 
566
- VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
567
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
663
+ def polymorphic_name
664
+ active_record.polymorphic_name
665
+ end
568
666
 
569
667
  def add_as_source(seed)
570
668
  seed
@@ -583,10 +681,6 @@ module ActiveRecord
583
681
  end
584
682
 
585
683
  private
586
- def calculate_constructable(macro, options)
587
- true
588
- end
589
-
590
684
  # Attempts to find the inverse association name automatically.
591
685
  # If it cannot find a suitable inverse association name, it returns
592
686
  # +nil+.
@@ -605,7 +699,9 @@ module ActiveRecord
605
699
 
606
700
  begin
607
701
  reflection = klass._reflect_on_association(inverse_name)
608
- rescue NameError
702
+ rescue NameError => error
703
+ raise unless error.name.to_s == class_name
704
+
609
705
  # Give up: we couldn't compute the klass type so we won't be able
610
706
  # to find any associations either.
611
707
  reflection = false
@@ -623,9 +719,10 @@ module ActiveRecord
623
719
  # with the current reflection's klass name.
624
720
  def valid_inverse_reflection?(reflection)
625
721
  reflection &&
722
+ reflection != self &&
626
723
  foreign_key == reflection.foreign_key &&
627
724
  klass <= reflection.active_record &&
628
- can_find_inverse_of_automatically?(reflection)
725
+ can_find_inverse_of_automatically?(reflection, true)
629
726
  end
630
727
 
631
728
  # Checks to see if the reflection doesn't have any options that prevent
@@ -634,14 +731,25 @@ module ActiveRecord
634
731
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
635
732
  # Third, we must not have options such as <tt>:foreign_key</tt>
636
733
  # 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)
734
+ def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
641
735
  reflection.options[:inverse_of] != false &&
642
- VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) &&
643
- !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] } &&
736
+ !reflection.options[:through] &&
737
+ !reflection.options[:foreign_key] &&
738
+ scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
739
+ end
740
+
741
+ # Scopes on the potential inverse reflection prevent automatic
742
+ # <tt>inverse_of</tt>, since the scope could exclude the owner record
743
+ # we would inverse from. Scopes on the reflection itself allow for
744
+ # automatic <tt>inverse_of</tt> as long as
745
+ # <tt>config.active_record.automatic_scope_inversing<tt> is set to
746
+ # +true+ (the default for new applications).
747
+ def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
748
+ if inverse_reflection
644
749
  !reflection.scope
750
+ else
751
+ !reflection.scope || reflection.klass.automatic_scope_inversing
752
+ end
645
753
  end
646
754
 
647
755
  def derive_class_name
@@ -650,13 +758,53 @@ module ActiveRecord
650
758
  class_name.camelize
651
759
  end
652
760
 
653
- def derive_foreign_key
761
+ def derive_foreign_key(infer_from_inverse_of: true)
654
762
  if belongs_to?
655
763
  "#{name}_id"
656
764
  elsif options[:as]
657
765
  "#{options[:as]}_id"
766
+ elsif options[:inverse_of] && infer_from_inverse_of
767
+ inverse_of.foreign_key(infer_from_inverse_of: false)
658
768
  else
659
- active_record.name.foreign_key
769
+ active_record.model_name.to_s.foreign_key
770
+ end
771
+ end
772
+
773
+ def derive_fk_query_constraints(foreign_key)
774
+ primary_query_constraints = active_record.query_constraints_list
775
+ owner_pk = active_record.primary_key
776
+
777
+ if primary_query_constraints.size != 2
778
+ raise ArgumentError, <<~MSG.squish
779
+ The query constraints list on the `#{active_record}` model has more than 2
780
+ attributes. Active Record is unable to derive the query constraints
781
+ for the association. You need to explicitly define the query constraints
782
+ for this association.
783
+ MSG
784
+ end
785
+
786
+ if !primary_query_constraints.include?(owner_pk)
787
+ raise ArgumentError, <<~MSG.squish
788
+ The query constraints on the `#{active_record}` model does not include the primary
789
+ key so Active Record is unable to derive the foreign key constraints for
790
+ the association. You need to explicitly define the query constraints for this
791
+ association.
792
+ MSG
793
+ end
794
+
795
+ first_key, last_key = primary_query_constraints
796
+
797
+ if first_key == owner_pk
798
+ [foreign_key, last_key.to_s]
799
+ elsif last_key == owner_pk
800
+ [first_key.to_s, foreign_key]
801
+ else
802
+ raise ArgumentError, <<~MSG.squish
803
+ Active Record couldn't correctly interpret the query constraints
804
+ for the `#{active_record}` model. The query constraints on `#{active_record}` are
805
+ `#{primary_query_constraints}` and the foreign key is `#{foreign_key}`.
806
+ You need to explicitly set the query constraints for this association.
807
+ MSG
660
808
  end
661
809
  end
662
810
 
@@ -691,11 +839,6 @@ module ActiveRecord
691
839
  Associations::HasOneAssociation
692
840
  end
693
841
  end
694
-
695
- private
696
- def calculate_constructable(macro, options)
697
- !options[:through]
698
- end
699
842
  end
700
843
 
701
844
  class BelongsToReflection < AssociationReflection # :nodoc:
@@ -715,6 +858,12 @@ module ActiveRecord
715
858
  def association_primary_key(klass = nil)
716
859
  if primary_key = options[:primary_key]
717
860
  @association_primary_key ||= -primary_key.to_s
861
+ elsif !polymorphic? && ((klass || self.klass).has_query_constraints? || options[:query_constraints])
862
+ (klass || self.klass).composite_query_constraints_list
863
+ elsif (klass || self.klass).composite_primary_key?
864
+ # If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
865
+ primary_key = (klass || self.klass).primary_key
866
+ primary_key.include?("id") ? "id" : primary_key
718
867
  else
719
868
  primary_key(klass || self.klass)
720
869
  end
@@ -733,13 +882,9 @@ module ActiveRecord
733
882
  end
734
883
 
735
884
  private
736
- def can_find_inverse_of_automatically?(_)
885
+ def can_find_inverse_of_automatically?(*)
737
886
  !polymorphic? && super
738
887
  end
739
-
740
- def calculate_constructable(macro, options)
741
- !polymorphic?
742
- end
743
888
  end
744
889
 
745
890
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -752,14 +897,17 @@ module ActiveRecord
752
897
 
753
898
  # Holds all the metadata about a :through association as it was specified
754
899
  # in the Active Record class.
755
- class ThroughReflection < AbstractReflection #:nodoc:
900
+ class ThroughReflection < AbstractReflection # :nodoc:
756
901
  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
902
  :active_record_primary_key, :join_foreign_key, to: :source_reflection
758
903
 
759
904
  def initialize(delegate_reflection)
905
+ super()
760
906
  @delegate_reflection = delegate_reflection
761
907
  @klass = delegate_reflection.options[:anonymous_class]
762
908
  @source_reflection_name = delegate_reflection.options[:source]
909
+
910
+ ensure_option_not_given_as_class!(:source_type)
763
911
  end
764
912
 
765
913
  def through_reflection?
@@ -840,8 +988,8 @@ module ActiveRecord
840
988
  source_reflection.scopes + super
841
989
  end
842
990
 
843
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
- source_reflection.join_scopes(table, predicate_builder, klass) + super
991
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
992
+ source_reflection.join_scopes(table, predicate_builder, klass, record) + super
845
993
  end
846
994
 
847
995
  def has_scope?
@@ -888,24 +1036,23 @@ module ActiveRecord
888
1036
  end
889
1037
 
890
1038
  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
- )
1039
+ @source_reflection_name ||= begin
1040
+ names = [name.to_s.singularize, name].collect(&:to_sym).uniq
1041
+ names = names.find_all { |n|
1042
+ through_reflection.klass._reflect_on_association(n)
1043
+ }
1044
+
1045
+ if names.length > 1
1046
+ raise AmbiguousSourceReflectionForThroughAssociation.new(
1047
+ active_record.name,
1048
+ macro,
1049
+ name,
1050
+ options,
1051
+ source_reflection_names
1052
+ )
1053
+ end
1054
+ names.first
906
1055
  end
907
-
908
- @source_reflection_name = names.first
909
1056
  end
910
1057
 
911
1058
  def source_options
@@ -1009,13 +1156,14 @@ module ActiveRecord
1009
1156
  :name, :scope_for, to: :@reflection
1010
1157
 
1011
1158
  def initialize(reflection, previous_reflection)
1159
+ super()
1012
1160
  @reflection = reflection
1013
1161
  @previous_reflection = previous_reflection
1014
1162
  end
1015
1163
 
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)
1164
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1165
+ scopes = @previous_reflection.join_scopes(table, predicate_builder, klass, record) + super
1166
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
1019
1167
  end
1020
1168
 
1021
1169
  def constraints
@@ -1034,6 +1182,7 @@ module ActiveRecord
1034
1182
  delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1035
1183
 
1036
1184
  def initialize(reflection, association)
1185
+ super()
1037
1186
  @reflection = reflection
1038
1187
  @association = association
1039
1188
  end