activerecord 5.2.8.1 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +849 -630
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +5 -4
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +95 -42
  10. data/lib/active_record/associations/association_scope.rb +21 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +50 -46
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
  13. data/lib/active_record/associations/builder/association.rb +23 -21
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +31 -29
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +41 -20
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +71 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +133 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +45 -8
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +2 -15
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  95. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  100. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
  108. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  110. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  113. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  114. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  115. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  116. data/lib/active_record/connection_adapters.rb +50 -0
  117. data/lib/active_record/connection_handling.rb +285 -33
  118. data/lib/active_record/core.rb +304 -106
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  121. data/lib/active_record/database_configurations/database_config.rb +80 -0
  122. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  123. data/lib/active_record/database_configurations/url_config.rb +53 -0
  124. data/lib/active_record/database_configurations.rb +272 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +71 -17
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +197 -481
  138. data/lib/active_record/gem_version.rb +4 -4
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +26 -22
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +34 -35
  147. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector.rb +77 -0
  150. data/lib/active_record/migration/command_recorder.rb +96 -44
  151. data/lib/active_record/migration/compatibility.rb +141 -64
  152. data/lib/active_record/migration/join_table.rb +0 -1
  153. data/lib/active_record/migration.rb +205 -156
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +113 -74
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +402 -78
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +153 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +58 -40
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +472 -186
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +108 -58
  185. data/lib/active_record/relation.rb +375 -104
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -6
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +39 -43
  202. data/lib/active_record/tasks/database_tasks.rb +276 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +246 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +58 -116
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +120 -35
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
data/MIT-LICENSE CHANGED
@@ -1,4 +1,6 @@
1
- Copyright (c) 2004-2018 David Heinemeier Hansson
1
+ Copyright (c) 2004-2020 David Heinemeier Hansson
2
+
3
+ Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -13,6 +13,8 @@ columns. Although these mappings can be defined explicitly, it's recommended
13
13
  to follow naming conventions, especially when getting started with the
14
14
  library.
15
15
 
16
+ You can read more about Active Record in the {Active Record Basics}[https://edgeguides.rubyonrails.org/active_record_basics.html] guide.
17
+
16
18
  A short rundown of some of the major features:
17
19
 
18
20
  * Automated mapping between classes and tables, attributes and columns.
@@ -130,7 +132,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
130
132
  SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
131
133
 
132
134
 
133
- * Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
135
+ * Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-doc.org/stdlib/libdoc/logger/rdoc/].
134
136
 
135
137
  ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
136
138
  ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
@@ -138,7 +140,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
138
140
 
139
141
  * Database agnostic schema management with Migrations.
140
142
 
141
- class AddSystemSettings < ActiveRecord::Migration[5.0]
143
+ class AddSystemSettings < ActiveRecord::Migration[6.0]
142
144
  def up
143
145
  create_table :system_settings do |t|
144
146
  t.string :name
@@ -192,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
192
194
 
193
195
  Source code can be downloaded as part of the Rails project on GitHub:
194
196
 
195
- * https://github.com/rails/rails/tree/5-2-stable/activerecord
197
+ * https://github.com/rails/rails/tree/master/activerecord
196
198
 
197
199
 
198
200
  == License
@@ -206,7 +208,7 @@ Active Record is released under the MIT license:
206
208
 
207
209
  API documentation is at:
208
210
 
209
- * http://api.rubyonrails.org
211
+ * https://api.rubyonrails.org
210
212
 
211
213
  Bug reports for the Ruby on Rails project can be filed here:
212
214
 
@@ -214,4 +216,4 @@ Bug reports for the Ruby on Rails project can be filed here:
214
216
 
215
217
  Feature requests should be discussed on the rails-core mailing list here:
216
218
 
217
- * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
219
+ * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -176,7 +176,7 @@ Benchmark.ips(TIME) do |x|
176
176
  end
177
177
 
178
178
  x.report "Model.log" do
179
- Exhibit.connection.send(:log, "hello", "world") {}
179
+ Exhibit.connection.send(:log, "hello", "world") { }
180
180
  end
181
181
 
182
182
  x.report "AR.execute(query)" do
@@ -3,8 +3,6 @@
3
3
  module ActiveRecord
4
4
  # See ActiveRecord::Aggregations::ClassMethods for documentation
5
5
  module Aggregations
6
- extend ActiveSupport::Concern
7
-
8
6
  def initialize_dup(*) # :nodoc:
9
7
  @aggregation_cache = {}
10
8
  super
@@ -16,7 +14,6 @@ module ActiveRecord
16
14
  end
17
15
 
18
16
  private
19
-
20
17
  def clear_aggregation_cache
21
18
  @aggregation_cache.clear if persisted?
22
19
  end
@@ -144,7 +141,7 @@ module ActiveRecord
144
141
  # converted to an instance of value class if necessary.
145
142
  #
146
143
  # For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be
147
- # aggregated using the +NetAddr::CIDR+ value class (http://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
144
+ # aggregated using the +NetAddr::CIDR+ value class (https://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
148
145
  # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
149
146
  # New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string
150
147
  # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
@@ -225,6 +222,10 @@ module ActiveRecord
225
222
  def composed_of(part_id, options = {})
226
223
  options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
227
224
 
225
+ unless self < Aggregations
226
+ include Aggregations
227
+ end
228
+
228
229
  name = part_id.id2name
229
230
  class_name = options[:class_name] || name.camelize
230
231
  mapping = options[:mapping] || [ name, name ]
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- class AssociationRelation < Relation
5
- def initialize(klass, association)
4
+ class AssociationRelation < Relation # :nodoc:
5
+ def initialize(klass, association, **)
6
6
  super(klass)
7
7
  @association = association
8
8
  end
@@ -15,20 +15,30 @@ module ActiveRecord
15
15
  other == records
16
16
  end
17
17
 
18
- def build(*args, &block)
19
- scoping { @association.build(*args, &block) }
20
- end
21
- alias new build
22
-
23
- def create(*args, &block)
24
- scoping { @association.create(*args, &block) }
25
- end
18
+ %w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
19
+ class_eval <<~RUBY
20
+ def #{method}(attributes, **kwargs)
21
+ if @association.reflection.through_reflection?
22
+ raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
23
+ end
26
24
 
27
- def create!(*args, &block)
28
- scoping { @association.create!(*args, &block) }
25
+ scoping { klass.#{method}(attributes, **kwargs) }
26
+ end
27
+ RUBY
29
28
  end
30
29
 
31
30
  private
31
+ def _new(attributes, &block)
32
+ @association.build(attributes, &block)
33
+ end
34
+
35
+ def _create(attributes, &block)
36
+ @association.create(attributes, &block)
37
+ end
38
+
39
+ def _create!(attributes, &block)
40
+ @association.create!(attributes, &block)
41
+ end
32
42
 
33
43
  def exec_queries
34
44
  super do |record|
@@ -6,9 +6,14 @@ module ActiveRecord
6
6
  module Associations
7
7
  # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
8
8
  class AliasTracker # :nodoc:
9
- def self.create(connection, initial_table, joins)
9
+ def self.create(connection, initial_table, joins, aliases = nil)
10
10
  if joins.empty?
11
- aliases = Hash.new(0)
11
+ aliases ||= Hash.new(0)
12
+ elsif aliases
13
+ default_proc = aliases.default_proc || proc { 0 }
14
+ aliases.default_proc = proc { |h, k|
15
+ h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
16
+ }
12
17
  else
13
18
  aliases = Hash.new { |h, k|
14
19
  h[k] = initial_count_for(connection, k, joins)
@@ -32,8 +37,6 @@ module ActiveRecord
32
37
  ).size
33
38
  elsif join.is_a?(Arel::Nodes::Join)
34
39
  join.left.name == name ? 1 : 0
35
- elsif join.is_a?(Hash)
36
- join[name]
37
40
  else
38
41
  raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
39
42
  end
@@ -48,31 +51,31 @@ module ActiveRecord
48
51
  @connection = connection
49
52
  end
50
53
 
51
- def aliased_table_for(table_name, aliased_name, type_caster)
52
- if aliases[table_name].zero?
54
+ def aliased_table_for(arel_table, table_name = nil)
55
+ table_name ||= arel_table.name
56
+
57
+ if aliases[table_name] == 0
53
58
  # If it's zero, we can have our table_name
54
59
  aliases[table_name] = 1
55
- Arel::Table.new(table_name, type_caster: type_caster)
60
+ arel_table = arel_table.alias(table_name) if arel_table.name != table_name
56
61
  else
57
62
  # Otherwise, we need to use an alias
58
- aliased_name = @connection.table_alias_for(aliased_name)
63
+ aliased_name = @connection.table_alias_for(yield)
59
64
 
60
65
  # Update the count
61
- aliases[aliased_name] += 1
66
+ count = aliases[aliased_name] += 1
62
67
 
63
- table_alias = if aliases[aliased_name] > 1
64
- "#{truncate(aliased_name)}_#{aliases[aliased_name]}"
65
- else
66
- aliased_name
67
- end
68
- Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
68
+ aliased_name = "#{truncate(aliased_name)}_#{count}" if count > 1
69
+
70
+ arel_table = arel_table.alias(aliased_name)
69
71
  end
72
+
73
+ arel_table
70
74
  end
71
75
 
72
76
  attr_reader :aliases
73
77
 
74
78
  private
75
-
76
79
  def truncate(name)
77
80
  name.slice(0, @connection.table_alias_length - 2)
78
81
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/array/wrap"
4
-
5
3
  module ActiveRecord
6
4
  module Associations
7
5
  # = Active Record Associations
@@ -17,6 +15,23 @@ module ActiveRecord
17
15
  # CollectionAssociation
18
16
  # HasManyAssociation + ForeignAssociation
19
17
  # HasManyThroughAssociation + ThroughAssociation
18
+ #
19
+ # Associations in Active Record are middlemen between the object that
20
+ # holds the association, known as the <tt>owner</tt>, and the associated
21
+ # result set, known as the <tt>target</tt>. Association metadata is available in
22
+ # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
23
+ #
24
+ # For example, given
25
+ #
26
+ # class Blog < ActiveRecord::Base
27
+ # has_many :posts
28
+ # end
29
+ #
30
+ # blog = Blog.first
31
+ #
32
+ # The association of <tt>blog.posts</tt> has the object +blog+ as its
33
+ # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
34
+ # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
20
35
  class Association #:nodoc:
21
36
  attr_reader :owner, :target, :reflection
22
37
 
@@ -39,8 +54,14 @@ module ActiveRecord
39
54
  @inversed = false
40
55
  end
41
56
 
57
+ def reset_negative_cache # :nodoc:
58
+ reset if loaded? && target.nil?
59
+ end
60
+
42
61
  # Reloads the \target and returns +self+ on success.
43
- def reload
62
+ # The QueryCache is cleared if +force+ is true.
63
+ def reload(force = false)
64
+ klass.connection.clear_query_cache if force && klass
44
65
  reset
45
66
  reset_scope
46
67
  load_target
@@ -76,18 +97,10 @@ module ActiveRecord
76
97
  end
77
98
 
78
99
  def scope
79
- target_scope.merge!(association_scope)
80
- end
81
-
82
- # The scope for this association.
83
- #
84
- # Note that the association_scope is merged into the target_scope only when the
85
- # scope method is called. This is because at that point the call may be surrounded
86
- # by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
87
- # actually gets built.
88
- def association_scope
89
- if klass
90
- @association_scope ||= AssociationScope.scope(self)
100
+ if (scope = klass.current_scope) && scope.try(:proxy_association) == self
101
+ scope.spawn
102
+ else
103
+ target_scope.merge!(association_scope)
91
104
  end
92
105
  end
93
106
 
@@ -121,7 +134,15 @@ module ActiveRecord
121
134
  self.target = record
122
135
  @inversed = !!record
123
136
  end
124
- alias :inversed_from_queries :inversed_from
137
+
138
+ def inversed_from_queries(record)
139
+ if inversable?(record)
140
+ self.target = record
141
+ @inversed = true
142
+ else
143
+ @inversed = false
144
+ end
145
+ end
125
146
 
126
147
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
127
148
  # polymorphic_type field on the owner.
@@ -129,12 +150,6 @@ module ActiveRecord
129
150
  reflection.klass
130
151
  end
131
152
 
132
- # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
133
- # through association's scope)
134
- def target_scope
135
- AssociationRelation.create(klass, self).merge!(klass.all)
136
- end
137
-
138
153
  def extensions
139
154
  extensions = klass.default_extensions | reflection.extensions
140
155
 
@@ -186,40 +201,60 @@ module ActiveRecord
186
201
  set_inverse_instance(record)
187
202
  end
188
203
 
189
- def create(attributes = {}, &block)
204
+ def create(attributes = nil, &block)
190
205
  _create_record(attributes, &block)
191
206
  end
192
207
 
193
- def create!(attributes = {}, &block)
208
+ def create!(attributes = nil, &block)
194
209
  _create_record(attributes, true, &block)
195
210
  end
196
211
 
197
212
  private
198
- def scope_for_create
199
- scope.scope_for_create
200
- end
213
+ def find_target
214
+ if owner.strict_loading? && owner.validation_context.nil?
215
+ Base.strict_loading_violation!(owner: owner.class, association: klass)
216
+ end
201
217
 
202
- def find_target?
203
- !loaded? && (!owner.new_record? || foreign_key_present?) && klass
204
- end
218
+ if reflection.strict_loading? && owner.validation_context.nil?
219
+ Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
220
+ end
221
+
222
+ scope = self.scope
223
+ return scope.to_a if skip_statement_cache?(scope)
205
224
 
206
- def creation_attributes
207
- attributes = {}
225
+ sc = reflection.association_scope_cache(klass, owner) do |params|
226
+ as = AssociationScope.create { params.bind }
227
+ target_scope.merge!(as.scope(self))
228
+ end
208
229
 
209
- if (reflection.has_one? || reflection.collection?) && !options[:through]
210
- attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
230
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
231
+ sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
232
+ end
211
233
 
212
- if reflection.type
213
- attributes[reflection.type] = owner.class.polymorphic_name
214
- end
234
+ # The scope for this association.
235
+ #
236
+ # Note that the association_scope is merged into the target_scope only when the
237
+ # scope method is called. This is because at that point the call may be surrounded
238
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
239
+ # actually gets built.
240
+ def association_scope
241
+ if klass
242
+ @association_scope ||= AssociationScope.scope(self)
215
243
  end
244
+ end
216
245
 
217
- attributes
246
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
247
+ # through association's scope)
248
+ def target_scope
249
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
218
250
  end
219
251
 
220
- # Sets the owner attributes on the given record
221
- def set_owner_attributes(record)
222
- creation_attributes.each { |key, value| record[key] = value }
252
+ def scope_for_create
253
+ scope.scope_for_create
254
+ end
255
+
256
+ def find_target?
257
+ !loaded? && (!owner.new_record? || foreign_key_present?) && klass
223
258
  end
224
259
 
225
260
  # Returns true if there is a foreign key present on the owner which
@@ -269,7 +304,7 @@ module ActiveRecord
269
304
 
270
305
  # Returns true if record contains the foreign_key
271
306
  def foreign_key_for?(record)
272
- record.has_attribute?(reflection.foreign_key)
307
+ record._has_attribute?(reflection.foreign_key)
273
308
  end
274
309
 
275
310
  # This should be implemented to return the values of the relevant key(s) on the owner,
@@ -294,6 +329,24 @@ module ActiveRecord
294
329
  klass.scope_attributes? ||
295
330
  reflection.source_reflection.active_record.default_scopes.any?
296
331
  end
332
+
333
+ def enqueue_destroy_association(options)
334
+ owner.class.destroy_association_async_job&.perform_later(**options)
335
+ end
336
+
337
+ def inversable?(record)
338
+ record &&
339
+ ((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
340
+ end
341
+
342
+ def matches_foreign_key?(record)
343
+ if foreign_key_for?(record)
344
+ record.read_attribute(reflection.foreign_key) == owner.id ||
345
+ (foreign_key_for?(owner) && owner.read_attribute(reflection.foreign_key) == record.id)
346
+ else
347
+ owner.read_attribute(reflection.foreign_key) == record.id
348
+ end
349
+ end
297
350
  end
298
351
  end
299
352
  end
@@ -26,7 +26,9 @@ module ActiveRecord
26
26
  chain = get_chain(reflection, association, scope.alias_tracker)
27
27
 
28
28
  scope.extending! reflection.extensions
29
- add_constraints(scope, owner, chain)
29
+ scope = add_constraints(scope, owner, chain)
30
+ scope.limit!(1) unless reflection.collection?
31
+ scope
30
32
  end
31
33
 
32
34
  def self.get_bind_values(owner, chain)
@@ -46,25 +48,20 @@ module ActiveRecord
46
48
  binds
47
49
  end
48
50
 
49
- # TODO Change this to private once we've dropped Ruby 2.2 support.
50
- # Workaround for Ruby 2.2 "private attribute?" warning.
51
- protected
52
-
51
+ private
53
52
  attr_reader :value_transformation
54
53
 
55
- private
56
54
  def join(table, constraint)
57
- table.create_join(table, table.create_on(constraint))
55
+ Arel::Nodes::LeadingJoin.new(table, Arel::Nodes::On.new(constraint))
58
56
  end
59
57
 
60
58
  def last_chain_scope(scope, reflection, owner)
61
- join_keys = reflection.join_keys
62
- key = join_keys.key
63
- foreign_key = join_keys.foreign_key
59
+ primary_key = reflection.join_primary_key
60
+ foreign_key = reflection.join_foreign_key
64
61
 
65
62
  table = reflection.aliased_table
66
63
  value = transform_value(owner[foreign_key])
67
- scope = apply_scope(scope, table, key, value)
64
+ scope = apply_scope(scope, table, primary_key, value)
68
65
 
69
66
  if reflection.type
70
67
  polymorphic_type = transform_value(owner.class.polymorphic_name)
@@ -79,13 +76,12 @@ module ActiveRecord
79
76
  end
80
77
 
81
78
  def next_chain_scope(scope, reflection, next_reflection)
82
- join_keys = reflection.join_keys
83
- key = join_keys.key
84
- foreign_key = join_keys.foreign_key
79
+ primary_key = reflection.join_primary_key
80
+ foreign_key = reflection.join_foreign_key
85
81
 
86
82
  table = reflection.aliased_table
87
83
  foreign_table = next_reflection.aliased_table
88
- constraint = table[key].eq(foreign_table[foreign_key])
84
+ constraint = table[primary_key].eq(foreign_table[foreign_key])
89
85
 
90
86
  if reflection.type
91
87
  value = transform_value(next_reflection.klass.polymorphic_name)
@@ -110,11 +106,9 @@ module ActiveRecord
110
106
  name = reflection.name
111
107
  chain = [Reflection::RuntimeReflection.new(reflection, association)]
112
108
  reflection.chain.drop(1).each do |refl|
113
- aliased_table = tracker.aliased_table_for(
114
- refl.table_name,
115
- refl.alias_candidate(name),
116
- refl.klass.type_caster
117
- )
109
+ aliased_table = tracker.aliased_table_for(refl.klass.arel_table) do
110
+ refl.alias_candidate(name)
111
+ end
118
112
  chain << ReflectionProxy.new(refl, aliased_table)
119
113
  end
120
114
  chain
@@ -136,10 +130,16 @@ module ActiveRecord
136
130
 
137
131
  if scope_chain_item == chain_head.scope
138
132
  scope.merge! item.except(:where, :includes, :unscope, :order)
133
+ elsif !item.references_values.empty?
134
+ join_dependency = item.construct_join_dependency(
135
+ item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
136
+ )
137
+ scope.joins!(*item.joins_values, join_dependency)
138
+ scope.left_outer_joins!(*item.left_outer_joins_values)
139
139
  end
140
140
 
141
141
  reflection.all_includes do
142
- scope.includes! item.includes_values
142
+ scope.includes_values |= item.includes_values
143
143
  end
144
144
 
145
145
  scope.unscope!(*item.unscope_values)
@@ -11,26 +11,23 @@ module ActiveRecord
11
11
  when :destroy
12
12
  target.destroy
13
13
  raise ActiveRecord::Rollback unless target.destroyed?
14
+ when :destroy_async
15
+ id = owner.public_send(reflection.foreign_key.to_sym)
16
+ primary_key_column = reflection.active_record_primary_key.to_sym
17
+
18
+ enqueue_destroy_association(
19
+ owner_model_name: owner.class.to_s,
20
+ owner_id: owner.id,
21
+ association_class: reflection.klass.to_s,
22
+ association_ids: [id],
23
+ association_primary_key_column: primary_key_column,
24
+ ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
25
+ )
14
26
  else
15
- target.send(options[:dependent])
27
+ target.public_send(options[:dependent])
16
28
  end
17
29
  end
18
30
 
19
- def replace(record)
20
- if record
21
- raise_on_type_mismatch!(record)
22
- update_counters_on_replace(record)
23
- set_inverse_instance(record)
24
- @updated = true
25
- else
26
- decrement_counters
27
- end
28
-
29
- replace_keys(record)
30
-
31
- self.target = record
32
- end
33
-
34
31
  def inversed_from(record)
35
32
  replace_keys(record)
36
33
  super
@@ -49,30 +46,60 @@ module ActiveRecord
49
46
  @updated
50
47
  end
51
48
 
52
- def decrement_counters # :nodoc:
49
+ def decrement_counters
53
50
  update_counters(-1)
54
51
  end
55
52
 
56
- def increment_counters # :nodoc:
53
+ def increment_counters
57
54
  update_counters(1)
58
55
  end
59
56
 
57
+ def decrement_counters_before_last_save
58
+ if reflection.polymorphic?
59
+ model_was = owner.attribute_before_last_save(reflection.foreign_type)&.constantize
60
+ else
61
+ model_was = klass
62
+ end
63
+
64
+ foreign_key_was = owner.attribute_before_last_save(reflection.foreign_key)
65
+
66
+ if foreign_key_was && model_was < ActiveRecord::Base
67
+ update_counters_via_scope(model_was, foreign_key_was, -1)
68
+ end
69
+ end
70
+
60
71
  def target_changed?
61
72
  owner.saved_change_to_attribute?(reflection.foreign_key)
62
73
  end
63
74
 
64
75
  private
76
+ def replace(record)
77
+ if record
78
+ raise_on_type_mismatch!(record)
79
+ set_inverse_instance(record)
80
+ @updated = true
81
+ end
82
+
83
+ replace_keys(record)
84
+
85
+ self.target = record
86
+ end
65
87
 
66
88
  def update_counters(by)
67
89
  if require_counter_update? && foreign_key_present?
68
90
  if target && !stale_target?
69
91
  target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
70
92
  else
71
- klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
93
+ update_counters_via_scope(klass, owner._read_attribute(reflection.foreign_key), by)
72
94
  end
73
95
  end
74
96
  end
75
97
 
98
+ def update_counters_via_scope(klass, foreign_key, by)
99
+ scope = klass.unscoped.where!(primary_key(klass) => foreign_key)
100
+ scope.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch])
101
+ end
102
+
76
103
  def find_target?
77
104
  !loaded? && foreign_key_present? && klass
78
105
  end
@@ -81,44 +108,21 @@ module ActiveRecord
81
108
  reflection.counter_cache_column && owner.persisted?
82
109
  end
83
110
 
84
- def update_counters_on_replace(record)
85
- if require_counter_update? && different_target?(record)
86
- owner.instance_variable_set :@_after_replace_counter_called, true
87
- record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
88
- decrement_counters
89
- end
90
- end
91
-
92
- # Checks whether record is different to the current target, without loading it
93
- def different_target?(record)
94
- record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
95
- end
96
-
97
111
  def replace_keys(record)
98
- owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
112
+ owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record.class)) : nil
99
113
  end
100
114
 
101
- def primary_key(record)
102
- reflection.association_primary_key(record.class)
115
+ def primary_key(klass)
116
+ reflection.association_primary_key(klass)
103
117
  end
104
118
 
105
119
  def foreign_key_present?
106
120
  owner._read_attribute(reflection.foreign_key)
107
121
  end
108
122
 
109
- # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
110
- # has_one associations.
111
123
  def invertible_for?(record)
112
124
  inverse = inverse_reflection_for(record)
113
- inverse && inverse.has_one?
114
- end
115
-
116
- def target_id
117
- if options[:primary_key]
118
- owner.send(reflection.name).try(:id)
119
- else
120
- owner._read_attribute(reflection.foreign_key)
121
- end
125
+ inverse && (inverse.has_one? || ActiveRecord::Base.has_many_inversing)
122
126
  end
123
127
 
124
128
  def stale_state