activerecord 5.1.5 → 5.2.1

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +450 -699
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +4 -2
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +33 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +52 -41
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -19
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +22 -67
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +17 -37
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +25 -214
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +16 -14
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +2 -0
  55. data/lib/active_record/collection_cache_key.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +149 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +20 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +79 -92
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +39 -60
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +17 -13
  133. data/lib/active_record/errors.rb +42 -3
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +4 -2
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +40 -2
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +196 -48
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +3 -1
  158. data/lib/active_record/railtie.rb +61 -3
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +110 -192
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +31 -9
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +71 -76
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +47 -20
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +55 -79
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +95 -91
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +3 -1
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +106 -219
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +6 -7
  193. data/lib/active_record/scoping/named.rb +21 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +22 -12
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +25 -14
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +32 -27
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +23 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2017 David Heinemeier Hansson
1
+ Copyright (c) 2004-2018 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -26,7 +26,7 @@ The Product class is automatically mapped to the table named "products",
26
26
  which might look like this:
27
27
 
28
28
  CREATE TABLE products (
29
- id int NOT NULL auto_increment,
29
+ id bigint NOT NULL auto_increment,
30
30
  name varchar(255),
31
31
  PRIMARY KEY (id)
32
32
  );
@@ -162,7 +162,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
162
162
  == Philosophy
163
163
 
164
164
  Active Record is an implementation of the object-relational mapping (ORM)
165
- pattern[http://www.martinfowler.com/eaaCatalog/activeRecord.html] by the same
165
+ pattern[https://www.martinfowler.com/eaaCatalog/activeRecord.html] by the same
166
166
  name described by Martin Fowler:
167
167
 
168
168
  "An object that wraps a row in a database table or view,
@@ -192,14 +192,14 @@ The latest version of Active Record can be installed with RubyGems:
192
192
 
193
193
  Source code can be downloaded as part of the Rails project on GitHub:
194
194
 
195
- * https://github.com/rails/rails/tree/master/activerecord
195
+ * https://github.com/rails/rails/tree/5-2-stable/activerecord
196
196
 
197
197
 
198
198
  == License
199
199
 
200
200
  Active Record is released under the MIT license:
201
201
 
202
- * http://www.opensource.org/licenses/MIT
202
+ * https://opensource.org/licenses/MIT
203
203
 
204
204
 
205
205
  == Support
@@ -208,7 +208,7 @@ API documentation is at:
208
208
 
209
209
  * http://api.rubyonrails.org
210
210
 
211
- Bug reports can be filed for the Ruby on Rails project here:
211
+ Bug reports for the Ruby on Rails project can be filed here:
212
212
 
213
213
  * https://github.com/rails/rails/issues
214
214
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record"
2
4
  require "benchmark/ips"
3
5
 
data/examples/simple.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record"
2
4
 
3
5
  class Person < ActiveRecord::Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # See ActiveRecord::Aggregations::ClassMethods for documentation
3
5
  module Aggregations
@@ -33,7 +35,7 @@ module ActiveRecord
33
35
  # the database).
34
36
  #
35
37
  # class Customer < ActiveRecord::Base
36
- # composed_of :balance, class_name: "Money", mapping: %w(amount currency)
38
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount)
37
39
  # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
38
40
  # end
39
41
  #
@@ -175,9 +177,9 @@ module ActiveRecord
175
177
  #
176
178
  # Once a #composed_of relationship is specified for a model, records can be loaded from the database
177
179
  # by specifying an instance of the value object in the conditions hash. The following example
178
- # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
180
+ # finds all customers with +address_street+ equal to "May Street" and +address_city+ equal to "Chicago":
179
181
  #
180
- # Customer.where(balance: Money.new(20, "USD"))
182
+ # Customer.where(address: Address.new("May Street", "Chicago"))
181
183
  #
182
184
  module ClassMethods
183
185
  # Adds reader and writer methods for manipulating a value object:
@@ -210,8 +212,7 @@ module ActiveRecord
210
212
  #
211
213
  # Option examples:
212
214
  # composed_of :temperature, mapping: %w(reading celsius)
213
- # composed_of :balance, class_name: "Money", mapping: %w(balance amount),
214
- # converter: Proc.new { |balance| balance.to_money }
215
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount)
215
216
  # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
216
217
  # composed_of :gps_location
217
218
  # composed_of :gps_location, allow_nil: true
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class AssociationRelation < Relation
3
- def initialize(klass, table, predicate_builder, association)
4
- super(klass, table, predicate_builder)
5
+ def initialize(klass, association)
6
+ super(klass)
5
7
  @association = association
6
8
  end
7
9
 
@@ -1,51 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/conversions"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
5
7
  # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
6
8
  class AliasTracker # :nodoc:
7
- attr_reader :aliases
8
-
9
- def self.create(connection, initial_table)
10
- aliases = Hash.new(0)
11
- aliases[initial_table] = 1
12
- new(connection, aliases)
13
- end
14
-
15
- def self.create_with_joins(connection, initial_table, joins)
9
+ def self.create(connection, initial_table, joins)
16
10
  if joins.empty?
17
- create(connection, initial_table)
11
+ aliases = Hash.new(0)
18
12
  else
19
13
  aliases = Hash.new { |h, k|
20
14
  h[k] = initial_count_for(connection, k, joins)
21
15
  }
22
- aliases[initial_table] = 1
23
- new(connection, aliases)
24
16
  end
17
+ aliases[initial_table] = 1
18
+ new(connection, aliases)
25
19
  end
26
20
 
27
21
  def self.initial_count_for(connection, name, table_joins)
28
- # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
29
- quoted_name = connection.quote_table_name(name).downcase
22
+ quoted_name = nil
30
23
 
31
24
  counts = table_joins.map do |join|
32
25
  if join.is_a?(Arel::Nodes::StringJoin)
26
+ # quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
27
+ quoted_name ||= connection.quote_table_name(name)
28
+
33
29
  # Table names + table aliases
34
- join.left.downcase.scan(
35
- /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
30
+ join.left.scan(
31
+ /JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
36
32
  ).size
37
- elsif join.respond_to? :left
38
- join.left.table_name == name ? 1 : 0
33
+ elsif join.is_a?(Arel::Nodes::Join)
34
+ join.left.name == name ? 1 : 0
35
+ elsif join.is_a?(Hash)
36
+ join[name]
39
37
  else
40
- # this branch is reached by two tests:
41
- #
42
- # activerecord/test/cases/associations/cascaded_eager_loading_test.rb:37
43
- # with :posts
44
- #
45
- # activerecord/test/cases/associations/eager_test.rb:1133
46
- # with :comments
47
- #
48
- 0
38
+ raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
49
39
  end
50
40
  end
51
41
 
@@ -79,6 +69,8 @@ module ActiveRecord
79
69
  end
80
70
  end
81
71
 
72
+ attr_reader :aliases
73
+
82
74
  private
83
75
 
84
76
  def truncate(name)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/array/wrap"
2
4
 
3
5
  module ActiveRecord
@@ -17,7 +19,6 @@ module ActiveRecord
17
19
  # HasManyThroughAssociation + ThroughAssociation
18
20
  class Association #:nodoc:
19
21
  attr_reader :owner, :target, :reflection
20
- attr_accessor :inversed
21
22
 
22
23
  delegate :options, to: :reflection
23
24
 
@@ -30,14 +31,6 @@ module ActiveRecord
30
31
  reset_scope
31
32
  end
32
33
 
33
- # Returns the name of the table of the associated class:
34
- #
35
- # post.comments.aliased_table_name # => "comments"
36
- #
37
- def aliased_table_name
38
- klass.table_name
39
- end
40
-
41
34
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
42
35
  def reset
43
36
  @loaded = false
@@ -73,7 +66,7 @@ module ActiveRecord
73
66
  #
74
67
  # Note that if the target has not been loaded, it is not considered stale.
75
68
  def stale_target?
76
- !inversed && loaded? && @stale_state != stale_state
69
+ !@inversed && loaded? && @stale_state != stale_state
77
70
  end
78
71
 
79
72
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -94,7 +87,7 @@ module ActiveRecord
94
87
  # actually gets built.
95
88
  def association_scope
96
89
  if klass
97
- @association_scope ||= AssociationScope.scope(self, klass.connection)
90
+ @association_scope ||= AssociationScope.scope(self)
98
91
  end
99
92
  end
100
93
 
@@ -104,23 +97,24 @@ module ActiveRecord
104
97
 
105
98
  # Set the inverse association, if possible
106
99
  def set_inverse_instance(record)
107
- if invertible_for?(record)
108
- inverse = record.association(inverse_reflection_for(record).name)
109
- inverse.target = owner
110
- inverse.inversed = true
100
+ if inverse = inverse_association_for(record)
101
+ inverse.inversed_from(owner)
111
102
  end
112
103
  record
113
104
  end
114
105
 
115
106
  # Remove the inverse association, if possible
116
107
  def remove_inverse_instance(record)
117
- if invertible_for?(record)
118
- inverse = record.association(inverse_reflection_for(record).name)
119
- inverse.target = nil
120
- inverse.inversed = false
108
+ if inverse = inverse_association_for(record)
109
+ inverse.inversed_from(nil)
121
110
  end
122
111
  end
123
112
 
113
+ def inversed_from(record)
114
+ self.target = record
115
+ @inversed = !!record
116
+ end
117
+
124
118
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
125
119
  # polymorphic_type field on the owner.
126
120
  def klass
@@ -130,14 +124,14 @@ module ActiveRecord
130
124
  # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
131
125
  # through association's scope)
132
126
  def target_scope
133
- AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all)
127
+ AssociationRelation.create(klass, self).merge!(klass.all)
134
128
  end
135
129
 
136
130
  def extensions
137
131
  extensions = klass.default_extensions | reflection.extensions
138
132
 
139
- if scope = reflection.scope
140
- extensions |= klass.unscoped.instance_exec(owner, &scope).extensions
133
+ if reflection.scope
134
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
141
135
  end
142
136
 
143
137
  extensions
@@ -162,17 +156,9 @@ module ActiveRecord
162
156
  reset
163
157
  end
164
158
 
165
- def interpolate(sql, record = nil)
166
- if sql.respond_to?(:to_proc)
167
- owner.instance_exec(record, &sql)
168
- else
169
- sql
170
- end
171
- end
172
-
173
- # We can't dump @reflection since it contains the scope proc
159
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
174
160
  def marshal_dump
175
- ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
161
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
176
162
  [@reflection.name, ivars]
177
163
  end
178
164
 
@@ -187,8 +173,8 @@ module ActiveRecord
187
173
  skip_assign = [reflection.foreign_key, reflection.type].compact
188
174
  assigned_keys = record.changed_attribute_names_to_save
189
175
  assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
190
- attributes = create_scope.except(*(assigned_keys - skip_assign))
191
- record.assign_attributes(attributes)
176
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
177
+ record.send(:_assign_attributes, attributes) if attributes.any?
192
178
  set_inverse_instance(record)
193
179
  end
194
180
 
@@ -201,6 +187,9 @@ module ActiveRecord
201
187
  end
202
188
 
203
189
  private
190
+ def scope_for_create
191
+ scope.scope_for_create
192
+ end
204
193
 
205
194
  def find_target?
206
195
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
@@ -212,8 +201,8 @@ module ActiveRecord
212
201
  if (reflection.has_one? || reflection.collection?) && !options[:through]
213
202
  attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
214
203
 
215
- if reflection.options[:as]
216
- attributes[reflection.type] = owner.class.base_class.name
204
+ if reflection.type
205
+ attributes[reflection.type] = owner.class.polymorphic_name
217
206
  end
218
207
  end
219
208
 
@@ -251,6 +240,12 @@ module ActiveRecord
251
240
  end
252
241
  end
253
242
 
243
+ def inverse_association_for(record)
244
+ if invertible_for?(record)
245
+ record.association(inverse_reflection_for(record).name)
246
+ end
247
+ end
248
+
254
249
  # Can be redefined by subclasses, notably polymorphic belongs_to
255
250
  # The record parameter is necessary to support polymorphic inverses as we must check for
256
251
  # the association in the specific class of the record.
@@ -280,11 +275,12 @@ module ActiveRecord
280
275
  def build_record(attributes)
281
276
  reflection.build_association(attributes) do |record|
282
277
  initialize_attributes(record, attributes)
278
+ yield(record) if block_given?
283
279
  end
284
280
  end
285
281
 
286
282
  # Returns true if statement cache should be skipped on the association reader.
287
- def skip_statement_cache?
283
+ def skip_statement_cache?(scope)
288
284
  reflection.has_scope? ||
289
285
  scope.eager_loading? ||
290
286
  klass.scope_attributes? ||
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class AssociationScope #:nodoc:
4
- def self.scope(association, connection)
5
- INSTANCE.scope(association, connection)
6
+ def self.scope(association)
7
+ INSTANCE.scope(association)
6
8
  end
7
9
 
8
10
  def self.create(&block)
@@ -16,20 +18,15 @@ module ActiveRecord
16
18
 
17
19
  INSTANCE = create
18
20
 
19
- def scope(association, connection)
21
+ def scope(association)
20
22
  klass = association.klass
21
23
  reflection = association.reflection
22
24
  scope = klass.unscoped
23
25
  owner = association.owner
24
- alias_tracker = AliasTracker.create connection, association.klass.table_name
25
- chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
26
+ chain = get_chain(reflection, association, scope.alias_tracker)
26
27
 
27
28
  scope.extending! reflection.extensions
28
- add_constraints(scope, owner, reflection, chain_head, chain_tail)
29
- end
30
-
31
- def join_type
32
- Arel::Nodes::InnerJoin
29
+ add_constraints(scope, owner, chain)
33
30
  end
34
31
 
35
32
  def self.get_bind_values(owner, chain)
@@ -38,12 +35,12 @@ module ActiveRecord
38
35
 
39
36
  binds << last_reflection.join_id_for(owner)
40
37
  if last_reflection.type
41
- binds << owner.class.base_class.name
38
+ binds << owner.class.polymorphic_name
42
39
  end
43
40
 
44
41
  chain.each_cons(2).each do |reflection, next_reflection|
45
42
  if reflection.type
46
- binds << next_reflection.klass.base_class.name
43
+ binds << next_reflection.klass.polymorphic_name
47
44
  end
48
45
  end
49
46
  binds
@@ -57,19 +54,20 @@ module ActiveRecord
57
54
 
58
55
  private
59
56
  def join(table, constraint)
60
- table.create_join(table, table.create_on(constraint), join_type)
57
+ table.create_join(table, table.create_on(constraint))
61
58
  end
62
59
 
63
- def last_chain_scope(scope, table, reflection, owner)
60
+ def last_chain_scope(scope, reflection, owner)
64
61
  join_keys = reflection.join_keys
65
62
  key = join_keys.key
66
63
  foreign_key = join_keys.foreign_key
67
64
 
65
+ table = reflection.aliased_table
68
66
  value = transform_value(owner[foreign_key])
69
67
  scope = apply_scope(scope, table, key, value)
70
68
 
71
69
  if reflection.type
72
- polymorphic_type = transform_value(owner.class.base_class.name)
70
+ polymorphic_type = transform_value(owner.class.polymorphic_name)
73
71
  scope = apply_scope(scope, table, reflection.type, polymorphic_type)
74
72
  end
75
73
 
@@ -80,15 +78,17 @@ module ActiveRecord
80
78
  value_transformation.call(value)
81
79
  end
82
80
 
83
- def next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
81
+ def next_chain_scope(scope, reflection, next_reflection)
84
82
  join_keys = reflection.join_keys
85
83
  key = join_keys.key
86
84
  foreign_key = join_keys.foreign_key
87
85
 
86
+ table = reflection.aliased_table
87
+ foreign_table = next_reflection.aliased_table
88
88
  constraint = table[key].eq(foreign_table[foreign_key])
89
89
 
90
90
  if reflection.type
91
- value = transform_value(next_reflection.klass.base_class.name)
91
+ value = transform_value(next_reflection.klass.polymorphic_name)
92
92
  scope = apply_scope(scope, table, reflection.type, value)
93
93
  end
94
94
 
@@ -96,12 +96,11 @@ module ActiveRecord
96
96
  end
97
97
 
98
98
  class ReflectionProxy < SimpleDelegator # :nodoc:
99
- attr_accessor :next
100
- attr_reader :alias_name
99
+ attr_reader :aliased_table
101
100
 
102
- def initialize(reflection, alias_name)
101
+ def initialize(reflection, aliased_table)
103
102
  super(reflection)
104
- @alias_name = alias_name
103
+ @aliased_table = aliased_table
105
104
  end
106
105
 
107
106
  def all_includes; nil; end
@@ -109,43 +108,34 @@ module ActiveRecord
109
108
 
110
109
  def get_chain(reflection, association, tracker)
111
110
  name = reflection.name
112
- runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
113
- previous_reflection = runtime_reflection
111
+ chain = [Reflection::RuntimeReflection.new(reflection, association)]
114
112
  reflection.chain.drop(1).each do |refl|
115
- alias_name = tracker.aliased_table_for(
113
+ aliased_table = tracker.aliased_table_for(
116
114
  refl.table_name,
117
115
  refl.alias_candidate(name),
118
116
  refl.klass.type_caster
119
117
  )
120
- proxy = ReflectionProxy.new(refl, alias_name)
121
- previous_reflection.next = proxy
122
- previous_reflection = proxy
118
+ chain << ReflectionProxy.new(refl, aliased_table)
123
119
  end
124
- [runtime_reflection, previous_reflection]
120
+ chain
125
121
  end
126
122
 
127
- def add_constraints(scope, owner, refl, chain_head, chain_tail)
128
- owner_reflection = chain_tail
129
- table = owner_reflection.alias_name
130
- scope = last_chain_scope(scope, table, owner_reflection, owner)
131
-
132
- reflection = chain_head
133
- while reflection
134
- table = reflection.alias_name
135
- next_reflection = reflection.next
123
+ def add_constraints(scope, owner, chain)
124
+ scope = last_chain_scope(scope, chain.last, owner)
136
125
 
137
- unless reflection == chain_tail
138
- foreign_table = next_reflection.alias_name
139
- scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
140
- end
126
+ chain.each_cons(2) do |reflection, next_reflection|
127
+ scope = next_chain_scope(scope, reflection, next_reflection)
128
+ end
141
129
 
130
+ chain_head = chain.first
131
+ chain.reverse_each do |reflection|
142
132
  # Exclude the scope of the association itself, because that
143
133
  # was already merged in the #scope method.
144
134
  reflection.constraints.each do |scope_chain_item|
145
- item = eval_scope(reflection.klass, table, scope_chain_item, owner)
135
+ item = eval_scope(reflection, scope_chain_item, owner)
146
136
 
147
- if scope_chain_item == refl.scope
148
- scope.merge! item.except(:where, :includes)
137
+ if scope_chain_item == chain_head.scope
138
+ scope.merge! item.except(:where, :includes, :unscope, :order)
149
139
  end
150
140
 
151
141
  reflection.all_includes do
@@ -154,10 +144,8 @@ module ActiveRecord
154
144
 
155
145
  scope.unscope!(*item.unscope_values)
156
146
  scope.where_clause += item.where_clause
157
- scope.order_values |= item.order_values
147
+ scope.order_values = item.order_values | scope.order_values
158
148
  end
159
-
160
- reflection = next_reflection
161
149
  end
162
150
 
163
151
  scope
@@ -171,9 +159,9 @@ module ActiveRecord
171
159
  end
172
160
  end
173
161
 
174
- def eval_scope(klass, table, scope, owner)
175
- predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
176
- ActiveRecord::Relation.create(klass, table, predicate_builder).instance_exec(owner, &scope)
162
+ def eval_scope(reflection, scope, owner)
163
+ relation = reflection.build_scope(reflection.aliased_table)
164
+ relation.instance_exec(owner, &scope) || relation
177
165
  end
178
166
  end
179
167
  end
@@ -1,26 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Belongs To Association
3
4
  module Associations
5
+ # = Active Record Belongs To Association
4
6
  class BelongsToAssociation < SingularAssociation #:nodoc:
5
7
  def handle_dependency
6
- target.send(options[:dependent]) if load_target
8
+ return unless load_target
9
+
10
+ case options[:dependent]
11
+ when :destroy
12
+ target.destroy
13
+ raise ActiveRecord::Rollback unless target.destroyed?
14
+ else
15
+ target.send(options[:dependent])
16
+ end
7
17
  end
8
18
 
9
19
  def replace(record)
10
20
  if record
11
21
  raise_on_type_mismatch!(record)
12
22
  update_counters_on_replace(record)
13
- replace_keys(record)
14
23
  set_inverse_instance(record)
15
24
  @updated = true
16
25
  else
17
26
  decrement_counters
18
- remove_keys
19
27
  end
20
28
 
29
+ replace_keys(record)
30
+
21
31
  self.target = record
22
32
  end
23
33
 
34
+ def inversed_from(record)
35
+ replace_keys(record)
36
+ super
37
+ end
38
+
24
39
  def default(&block)
25
40
  writer(owner.instance_exec(&block)) if reader.nil?
26
41
  end
@@ -42,6 +57,10 @@ module ActiveRecord
42
57
  update_counters(1)
43
58
  end
44
59
 
60
+ def target_changed?
61
+ owner.saved_change_to_attribute?(reflection.foreign_key)
62
+ end
63
+
45
64
  private
46
65
 
47
66
  def update_counters(by)
@@ -65,22 +84,22 @@ module ActiveRecord
65
84
  def update_counters_on_replace(record)
66
85
  if require_counter_update? && different_target?(record)
67
86
  owner.instance_variable_set :@_after_replace_counter_called, true
68
- record.increment!(reflection.counter_cache_column)
87
+ record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
69
88
  decrement_counters
70
89
  end
71
90
  end
72
91
 
73
92
  # Checks whether record is different to the current target, without loading it
74
93
  def different_target?(record)
75
- record.id != owner._read_attribute(reflection.foreign_key)
94
+ record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
76
95
  end
77
96
 
78
97
  def replace_keys(record)
79
- owner[reflection.foreign_key] = record._read_attribute(reflection.association_primary_key(record.class))
98
+ owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
80
99
  end
81
100
 
82
- def remove_keys
83
- owner[reflection.foreign_key] = nil
101
+ def primary_key(record)
102
+ reflection.association_primary_key(record.class)
84
103
  end
85
104
 
86
105
  def foreign_key_present?
@@ -1,22 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Belongs To Polymorphic Association
3
4
  module Associations
5
+ # = Active Record Belongs To Polymorphic Association
4
6
  class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
5
7
  def klass
6
8
  type = owner[reflection.foreign_type]
7
9
  type.presence && type.constantize
8
10
  end
9
11
 
10
- private
12
+ def target_changed?
13
+ super || owner.saved_change_to_attribute?(reflection.foreign_type)
14
+ end
11
15
 
16
+ private
12
17
  def replace_keys(record)
13
18
  super
14
- owner[reflection.foreign_type] = record.class.base_class.name
15
- end
16
-
17
- def remove_keys
18
- super
19
- owner[reflection.foreign_type] = nil
19
+ owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
20
20
  end
21
21
 
22
22
  def different_target?(record)