activerecord 5.1.7 → 5.2.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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +372 -765
  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 +16 -27
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +20 -10
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +4 -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 +43 -35
  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 +7 -18
  26. data/lib/active_record/associations/has_one_association.rb +4 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +8 -7
  28. data/lib/active_record/associations/join_dependency/join_association.rb +17 -56
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
  31. data/lib/active_record/associations/join_dependency.rb +23 -43
  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 -10
  36. data/lib/active_record/associations/through_association.rb +25 -10
  37. data/lib/active_record/associations.rb +31 -54
  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 +8 -2
  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 +6 -5
  50. data/lib/active_record/autosave_association.rb +8 -11
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +8 -10
  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 +111 -38
  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 +13 -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 +57 -2
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +111 -183
  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 +11 -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 +3 -11
  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 +2 -0
  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 +4 -6
  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 +246 -110
  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 +58 -82
  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 +18 -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 +71 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +80 -90
  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 +15 -12
  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 +54 -21
  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 +14 -17
  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 +16 -21
  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 +166 -16
  156. data/lib/active_record/query_cache.rb +11 -6
  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 +30 -8
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +75 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +51 -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 +53 -78
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +89 -88
  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 +95 -208
  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 +26 -15
  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 +5 -12
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +9 -7
  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 +2 -4
  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 +35 -5
  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 +24 -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 -122
  254. data/lib/active_record/attribute_set/builder.rb +0 -126
  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.fetch(name, 0)
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
@@ -30,14 +32,6 @@ module ActiveRecord
30
32
  reset_scope
31
33
  end
32
34
 
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
35
  # Resets the \loaded flag to +false+ and sets the \target to +nil+.
42
36
  def reset
43
37
  @loaded = false
@@ -94,7 +88,7 @@ module ActiveRecord
94
88
  # actually gets built.
95
89
  def association_scope
96
90
  if klass
97
- @association_scope ||= AssociationScope.scope(self, klass.connection)
91
+ @association_scope ||= AssociationScope.scope(self)
98
92
  end
99
93
  end
100
94
 
@@ -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
 
@@ -284,7 +273,7 @@ module ActiveRecord
284
273
  end
285
274
 
286
275
  # Returns true if statement cache should be skipped on the association reader.
287
- def skip_statement_cache?
276
+ def skip_statement_cache?(scope)
288
277
  reflection.has_scope? ||
289
278
  scope.eager_loading? ||
290
279
  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,39 @@
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
 
21
29
  self.target = record
22
30
  end
23
31
 
32
+ def target=(record)
33
+ replace_keys(record)
34
+ super
35
+ end
36
+
24
37
  def default(&block)
25
38
  writer(owner.instance_exec(&block)) if reader.nil?
26
39
  end
@@ -65,7 +78,7 @@ module ActiveRecord
65
78
  def update_counters_on_replace(record)
66
79
  if require_counter_update? && different_target?(record)
67
80
  owner.instance_variable_set :@_after_replace_counter_called, true
68
- record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
81
+ record.increment!(reflection.counter_cache_column)
69
82
  decrement_counters
70
83
  end
71
84
  end
@@ -76,11 +89,8 @@ module ActiveRecord
76
89
  end
77
90
 
78
91
  def replace_keys(record)
79
- owner[reflection.foreign_key] = record._read_attribute(reflection.association_primary_key(record.class))
80
- end
81
-
82
- def remove_keys
83
- owner[reflection.foreign_key] = nil
92
+ owner[reflection.foreign_key] = record ?
93
+ record._read_attribute(reflection.association_primary_key(record.class)) : nil
84
94
  end
85
95
 
86
96
  def foreign_key_present?
@@ -1,6 +1,8 @@
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]
@@ -11,12 +13,7 @@ module ActiveRecord
11
13
 
12
14
  def replace_keys(record)
13
15
  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
16
+ owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
20
17
  end
21
18
 
22
19
  def different_target?(record)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This is the parent Association class which defines the variables
2
4
  # used by all associations.
3
5
  #
@@ -36,11 +38,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
36
38
  def self.create_reflection(model, name, scope, options, extension = nil)
37
39
  raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
38
40
 
39
- if scope.is_a?(Hash)
40
- options = scope
41
- scope = nil
42
- end
43
-
44
41
  validate_options(options)
45
42
 
46
43
  scope = build_scope(scope, extension)
@@ -107,8 +104,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
107
104
 
108
105
  def self.define_readers(mixin, name)
109
106
  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
110
- def #{name}(*args)
111
- association(:#{name}).reader(*args)
107
+ def #{name}
108
+ association(:#{name}).reader
112
109
  end
113
110
  CODE
114
111
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class BelongsTo < SingularAssociation #:nodoc:
3
5
  def self.macro
@@ -32,9 +34,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
32
34
  foreign_key = reflection.foreign_key
33
35
  cache_column = reflection.counter_cache_column
34
36
 
35
- if (@_after_create_counter_called ||= false)
36
- @_after_create_counter_called = false
37
- elsif (@_after_replace_counter_called ||= false)
37
+ if (@_after_replace_counter_called ||= false)
38
38
  @_after_replace_counter_called = false
39
39
  elsif saved_change_to_attribute?(foreign_key) && !new_record?
40
40
  if reflection.polymorphic?
@@ -84,8 +84,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
84
84
  else
85
85
  klass = association.klass
86
86
  end
87
- primary_key = reflection.association_primary_key(klass)
88
- old_record = klass.find_by(primary_key => old_foreign_id)
87
+ old_record = klass.find_by(klass.primary_key => old_foreign_id)
89
88
 
90
89
  if old_record
91
90
  if touch != true
@@ -1,4 +1,4 @@
1
- # This class is inherited by the has_many and has_many_and_belongs_to_many association classes
1
+ # frozen_string_literal: true
2
2
 
3
3
  require "active_record/associations"
4
4
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasAndBelongsToMany # :nodoc:
3
5
  class JoinTableResolver # :nodoc:
@@ -45,7 +47,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
45
47
  habtm = JoinTableResolver.build lhs_model, association_name, options
46
48
 
47
49
  join_model = Class.new(ActiveRecord::Base) {
48
- class << self;
50
+ class << self
49
51
  attr_accessor :left_model
50
52
  attr_accessor :name
51
53
  attr_accessor :table_name_resolver
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasMany < CollectionAssociation #:nodoc:
3
5
  def self.macro
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations::Builder # :nodoc:
2
4
  class HasOne < SingularAssociation #:nodoc:
3
5
  def self.macro