activerecord 5.2.6 → 6.0.5

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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +928 -559
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +0 -1
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +107 -66
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +14 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -43
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +232 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +243 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +116 -29
  294. data/lib/active_record/collection_cache_key.rb +0 -53
data/MIT-LICENSE CHANGED
@@ -1,4 +1,6 @@
1
- Copyright (c) 2004-2018 David Heinemeier Hansson
1
+ Copyright (c) 2004-2019 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.
@@ -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/main/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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # This class is used to create a connection that we can use for advisory
5
+ # locks. This will take out a "global" lock that can't be accidentally
6
+ # removed if a new connection is established during a migration.
7
+ class AdvisoryLockBase < ActiveRecord::Base # :nodoc:
8
+ self.abstract_class = true
9
+
10
+ self.connection_specification_name = "AdvisoryLockBase"
11
+
12
+ class << self
13
+ def _internal?
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -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
@@ -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 ]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class AssociationRelation < Relation
5
- def initialize(klass, association)
5
+ def initialize(klass, association, **)
6
6
  super(klass)
7
7
  @association = association
8
8
  end
@@ -15,21 +15,23 @@ module ActiveRecord
15
15
  other == records
16
16
  end
17
17
 
18
- def build(*args, &block)
19
- scoping { @association.build(*args, &block) }
18
+ def build(attributes = nil, &block)
19
+ block = _deprecated_scope_block("new", &block)
20
+ scoping { @association.build(attributes, &block) }
20
21
  end
21
22
  alias new build
22
23
 
23
- def create(*args, &block)
24
- scoping { @association.create(*args, &block) }
24
+ def create(attributes = nil, &block)
25
+ block = _deprecated_scope_block("create", &block)
26
+ scoping { @association.create(attributes, &block) }
25
27
  end
26
28
 
27
- def create!(*args, &block)
28
- scoping { @association.create!(*args, &block) }
29
+ def create!(attributes = nil, &block)
30
+ block = _deprecated_scope_block("create!", &block)
31
+ scoping { @association.create!(attributes, &block) }
29
32
  end
30
33
 
31
34
  private
32
-
33
35
  def exec_queries
34
36
  super do |record|
35
37
  @association.set_inverse_instance_from_queries(record)
@@ -72,7 +72,6 @@ module ActiveRecord
72
72
  attr_reader :aliases
73
73
 
74
74
  private
75
-
76
75
  def truncate(name)
77
76
  name.slice(0, @connection.table_alias_length - 2)
78
77
  end
@@ -17,6 +17,23 @@ module ActiveRecord
17
17
  # CollectionAssociation
18
18
  # HasManyAssociation + ForeignAssociation
19
19
  # HasManyThroughAssociation + ThroughAssociation
20
+ #
21
+ # Associations in Active Record are middlemen between the object that
22
+ # holds the association, known as the <tt>owner</tt>, and the associated
23
+ # result set, known as the <tt>target</tt>. Association metadata is available in
24
+ # <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
25
+ #
26
+ # For example, given
27
+ #
28
+ # class Blog < ActiveRecord::Base
29
+ # has_many :posts
30
+ # end
31
+ #
32
+ # blog = Blog.first
33
+ #
34
+ # The association of <tt>blog.posts</tt> has the object +blog+ as its
35
+ # <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
36
+ # the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
20
37
  class Association #:nodoc:
21
38
  attr_reader :owner, :target, :reflection
22
39
 
@@ -40,7 +57,9 @@ module ActiveRecord
40
57
  end
41
58
 
42
59
  # Reloads the \target and returns +self+ on success.
43
- def reload
60
+ # The QueryCache is cleared if +force+ is true.
61
+ def reload(force = false)
62
+ klass.connection.clear_query_cache if force && klass
44
63
  reset
45
64
  reset_scope
46
65
  load_target
@@ -76,18 +95,10 @@ module ActiveRecord
76
95
  end
77
96
 
78
97
  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)
98
+ if (scope = klass.current_scope) && scope.try(:proxy_association) == self
99
+ scope.spawn
100
+ else
101
+ target_scope.merge!(association_scope)
91
102
  end
92
103
  end
93
104
 
@@ -129,12 +140,6 @@ module ActiveRecord
129
140
  reflection.klass
130
141
  end
131
142
 
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
143
  def extensions
139
144
  extensions = klass.default_extensions | reflection.extensions
140
145
 
@@ -195,6 +200,37 @@ module ActiveRecord
195
200
  end
196
201
 
197
202
  private
203
+ def find_target
204
+ scope = self.scope
205
+ return scope.to_a if skip_statement_cache?(scope)
206
+
207
+ sc = reflection.association_scope_cache(klass, owner) do |params|
208
+ as = AssociationScope.create { params.bind }
209
+ target_scope.merge!(as.scope(self))
210
+ end
211
+
212
+ binds = AssociationScope.get_bind_values(owner, reflection.chain)
213
+ sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) } || []
214
+ end
215
+
216
+ # The scope for this association.
217
+ #
218
+ # Note that the association_scope is merged into the target_scope only when the
219
+ # scope method is called. This is because at that point the call may be surrounded
220
+ # by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
221
+ # actually gets built.
222
+ def association_scope
223
+ if klass
224
+ @association_scope ||= AssociationScope.scope(self)
225
+ end
226
+ end
227
+
228
+ # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
229
+ # through association's scope)
230
+ def target_scope
231
+ AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
232
+ end
233
+
198
234
  def scope_for_create
199
235
  scope.scope_for_create
200
236
  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,15 +48,11 @@ 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
+ table.create_join(table, table.create_on(constraint), Arel::Nodes::LeadingJoin)
58
56
  end
59
57
 
60
58
  def last_chain_scope(scope, reflection, owner)
@@ -136,6 +134,12 @@ module ActiveRecord
136
134
 
137
135
  if scope_chain_item == chain_head.scope
138
136
  scope.merge! item.except(:where, :includes, :unscope, :order)
137
+ elsif !item.references_values.empty?
138
+ join_dependency = item.construct_join_dependency(
139
+ item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
140
+ )
141
+ scope.joins!(*item.joins_values, join_dependency)
142
+ scope.left_outer_joins!(*item.left_outer_joins_values)
139
143
  end
140
144
 
141
145
  reflection.all_includes do
@@ -16,21 +16,6 @@ module ActiveRecord
16
16
  end
17
17
  end
18
18
 
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
19
  def inversed_from(record)
35
20
  replace_keys(record)
36
21
  super
@@ -49,30 +34,60 @@ module ActiveRecord
49
34
  @updated
50
35
  end
51
36
 
52
- def decrement_counters # :nodoc:
37
+ def decrement_counters
53
38
  update_counters(-1)
54
39
  end
55
40
 
56
- def increment_counters # :nodoc:
41
+ def increment_counters
57
42
  update_counters(1)
58
43
  end
59
44
 
45
+ def decrement_counters_before_last_save
46
+ if reflection.polymorphic?
47
+ model_was = owner.attribute_before_last_save(reflection.foreign_type).try(:constantize)
48
+ else
49
+ model_was = klass
50
+ end
51
+
52
+ foreign_key_was = owner.attribute_before_last_save(reflection.foreign_key)
53
+
54
+ if foreign_key_was && model_was < ActiveRecord::Base
55
+ update_counters_via_scope(model_was, foreign_key_was, -1)
56
+ end
57
+ end
58
+
60
59
  def target_changed?
61
60
  owner.saved_change_to_attribute?(reflection.foreign_key)
62
61
  end
63
62
 
64
63
  private
64
+ def replace(record)
65
+ if record
66
+ raise_on_type_mismatch!(record)
67
+ set_inverse_instance(record)
68
+ @updated = true
69
+ end
70
+
71
+ replace_keys(record)
72
+
73
+ self.target = record
74
+ end
65
75
 
66
76
  def update_counters(by)
67
77
  if require_counter_update? && foreign_key_present?
68
78
  if target && !stale_target?
69
79
  target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
70
80
  else
71
- klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
81
+ update_counters_via_scope(klass, owner._read_attribute(reflection.foreign_key), by)
72
82
  end
73
83
  end
74
84
  end
75
85
 
86
+ def update_counters_via_scope(klass, foreign_key, by)
87
+ scope = klass.unscoped.where!(primary_key(klass) => foreign_key)
88
+ scope.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch])
89
+ end
90
+
76
91
  def find_target?
77
92
  !loaded? && foreign_key_present? && klass
78
93
  end
@@ -81,25 +96,12 @@ module ActiveRecord
81
96
  reflection.counter_cache_column && owner.persisted?
82
97
  end
83
98
 
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
99
  def replace_keys(record)
98
- owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
100
+ owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record.class)) : nil
99
101
  end
100
102
 
101
- def primary_key(record)
102
- reflection.association_primary_key(record.class)
103
+ def primary_key(klass)
104
+ reflection.association_primary_key(klass)
103
105
  end
104
106
 
105
107
  def foreign_key_present?
@@ -113,14 +115,6 @@ module ActiveRecord
113
115
  inverse && inverse.has_one?
114
116
  end
115
117
 
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
122
- end
123
-
124
118
  def stale_state
125
119
  result = owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
126
120
  result && result.to_s
@@ -19,10 +19,6 @@ module ActiveRecord
19
19
  owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
20
20
  end
21
21
 
22
- def different_target?(record)
23
- super || record.class != klass
24
- end
25
-
26
22
  def inverse_reflection_for(record)
27
23
  reflection.polymorphic_inverse_of(record.class)
28
24
  end
@@ -27,40 +27,32 @@ module ActiveRecord::Associations::Builder # :nodoc:
27
27
  "Please choose a different association name."
28
28
  end
29
29
 
30
- extension = define_extensions model, name, &block
31
- reflection = create_reflection model, name, scope, options, extension
30
+ reflection = create_reflection(model, name, scope, options, &block)
32
31
  define_accessors model, reflection
33
32
  define_callbacks model, reflection
34
33
  define_validations model, reflection
35
34
  reflection
36
35
  end
37
36
 
38
- def self.create_reflection(model, name, scope, options, extension = nil)
37
+ def self.create_reflection(model, name, scope, options, &block)
39
38
  raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
40
39
 
41
40
  validate_options(options)
42
41
 
43
- scope = build_scope(scope, extension)
42
+ extension = define_extensions(model, name, &block)
43
+ options[:extend] = [*options[:extend], extension] if extension
44
+
45
+ scope = build_scope(scope)
44
46
 
45
47
  ActiveRecord::Reflection.create(macro, name, scope, options, model)
46
48
  end
47
49
 
48
- def self.build_scope(scope, extension)
49
- new_scope = scope
50
-
50
+ def self.build_scope(scope)
51
51
  if scope && scope.arity == 0
52
- new_scope = proc { instance_exec(&scope) }
53
- end
54
-
55
- if extension
56
- new_scope = wrap_scope new_scope, extension
52
+ proc { instance_exec(&scope) }
53
+ else
54
+ scope
57
55
  end
58
-
59
- new_scope
60
- end
61
-
62
- def self.wrap_scope(scope, extension)
63
- scope
64
56
  end
65
57
 
66
58
  def self.macro
@@ -136,5 +128,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
136
128
  name = reflection.name
137
129
  model.before_destroy lambda { |o| o.association(name).handle_dependency }
138
130
  end
131
+
132
+ private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
133
+ :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
134
+ :valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
139
135
  end
140
136
  end
@@ -21,58 +21,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
21
21
  add_default_callbacks(model, reflection) if reflection.options[:default]
22
22
  end
23
23
 
24
- def self.define_accessors(mixin, reflection)
25
- super
26
- add_counter_cache_methods mixin
27
- end
28
-
29
- def self.add_counter_cache_methods(mixin)
30
- return if mixin.method_defined? :belongs_to_counter_cache_after_update
31
-
32
- mixin.class_eval do
33
- def belongs_to_counter_cache_after_update(reflection)
34
- foreign_key = reflection.foreign_key
35
- cache_column = reflection.counter_cache_column
36
-
37
- if (@_after_replace_counter_called ||= false)
38
- @_after_replace_counter_called = false
39
- elsif association(reflection.name).target_changed?
40
- if reflection.polymorphic?
41
- model = attribute_in_database(reflection.foreign_type).try(:constantize)
42
- model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
43
- else
44
- model = reflection.klass
45
- model_was = reflection.klass
46
- end
47
-
48
- foreign_key_was = attribute_before_last_save foreign_key
49
- foreign_key = attribute_in_database foreign_key
50
-
51
- if foreign_key && model.respond_to?(:increment_counter)
52
- foreign_key = counter_cache_target(reflection, model, foreign_key)
53
- model.increment_counter(cache_column, foreign_key)
54
- end
55
-
56
- if foreign_key_was && model_was.respond_to?(:decrement_counter)
57
- foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was)
58
- model_was.decrement_counter(cache_column, foreign_key_was)
59
- end
60
- end
61
- end
62
-
63
- private
64
- def counter_cache_target(reflection, model, foreign_key)
65
- primary_key = reflection.association_primary_key(model)
66
- model.unscoped.where!(primary_key => foreign_key)
67
- end
68
- end
69
- end
70
-
71
24
  def self.add_counter_cache_callbacks(model, reflection)
72
25
  cache_column = reflection.counter_cache_column
73
26
 
74
27
  model.after_update lambda { |record|
75
- record.belongs_to_counter_cache_after_update(reflection)
28
+ association = association(reflection.name)
29
+
30
+ if association.target_changed?
31
+ association.increment_counters
32
+ association.decrement_counters_before_last_save
33
+ end
76
34
  }
77
35
 
78
36
  klass = reflection.class_name.safe_constantize
@@ -116,19 +74,25 @@ module ActiveRecord::Associations::Builder # :nodoc:
116
74
 
117
75
  def self.add_touch_callbacks(model, reflection)
118
76
  foreign_key = reflection.foreign_key
119
- n = reflection.name
77
+ name = reflection.name
120
78
  touch = reflection.options[:touch]
121
79
 
122
80
  callback = lambda { |changes_method| lambda { |record|
123
- BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
81
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method)
124
82
  }}
125
83
 
126
- unless reflection.counter_cache_column
84
+ if reflection.counter_cache_column
85
+ touch_callback = callback.(:saved_changes)
86
+ update_callback = lambda { |record|
87
+ instance_exec(record, &touch_callback) unless association(reflection.name).target_changed?
88
+ }
89
+ model.after_update update_callback, if: :saved_changes?
90
+ else
127
91
  model.after_create callback.(:saved_changes), if: :saved_changes?
92
+ model.after_update callback.(:saved_changes), if: :saved_changes?
128
93
  model.after_destroy callback.(:changes_to_save)
129
94
  end
130
95
 
131
- model.after_update callback.(:saved_changes), if: :saved_changes?
132
96
  model.after_touch callback.(:changes_to_save)
133
97
  end
134
98
 
@@ -159,5 +123,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
159
123
  model.validates_presence_of reflection.name, message: :required
160
124
  end
161
125
  end
126
+
127
+ private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks, :define_validations,
128
+ :add_counter_cache_callbacks, :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
162
129
  end
163
130
  end
@@ -22,9 +22,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
22
22
 
23
23
  def self.define_extensions(model, name, &block)
24
24
  if block_given?
25
- extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
25
+ extension_module_name = "#{name.to_s.camelize}AssociationExtension"
26
26
  extension = Module.new(&block)
27
- model.parent.const_set(extension_module_name, extension)
27
+ model.const_set(extension_module_name, extension)
28
28
  end
29
29
  end
30
30
 
@@ -67,16 +67,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
67
67
  CODE
68
68
  end
69
69
 
70
- def self.wrap_scope(scope, mod)
71
- if scope
72
- if scope.arity > 0
73
- proc { |owner| instance_exec(owner, &scope).extending(mod) }
74
- else
75
- proc { instance_exec(&scope).extending(mod) }
76
- end
77
- else
78
- proc { extending(mod) }
79
- end
80
- end
70
+ private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
81
71
  end
82
72
  end