activerecord 5.1.7 → 5.2.4.3

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 +556 -685
  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.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +40 -63
  11. data/lib/active_record/associations/alias_tracker.rb +19 -27
  12. data/lib/active_record/associations/association.rb +41 -37
  13. data/lib/active_record/associations/association_scope.rb +38 -50
  14. data/lib/active_record/associations/belongs_to_association.rb +27 -8
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +12 -4
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +59 -47
  24. data/lib/active_record/associations/collection_proxy.rb +20 -49
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +12 -1
  27. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  28. data/lib/active_record/associations/has_one_association.rb +12 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +48 -93
  31. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/preloader/association.rb +45 -61
  36. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +26 -11
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +30 -214
  44. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +21 -9
  50. data/lib/active_record/attributes.rb +6 -5
  51. data/lib/active_record/autosave_association.rb +35 -19
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +8 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +12 -8
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  70. data/lib/active_record/connection_adapters/column.rb +3 -1
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +10 -3
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +42 -3
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +5 -3
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +14 -17
  146. data/lib/active_record/locking/pessimistic.rb +9 -6
  147. data/lib/active_record/log_subscriber.rb +43 -0
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +47 -9
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +16 -21
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +167 -16
  157. data/lib/active_record/query_cache.rb +6 -8
  158. data/lib/active_record/querying.rb +4 -2
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +46 -36
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +108 -194
  165. data/lib/active_record/relation.rb +120 -214
  166. data/lib/active_record/relation/batches.rb +20 -5
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +45 -19
  169. data/lib/active_record/relation/delegation.rb +45 -27
  170. data/lib/active_record/relation/finder_methods.rb +75 -76
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +128 -99
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -68
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +9 -8
  194. data/lib/active_record/scoping/default.rb +8 -9
  195. data/lib/active_record/scoping/named.rb +23 -7
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +23 -13
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +25 -14
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +6 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +33 -28
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +2 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +35 -5
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  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.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -126
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  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
@@ -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,32 @@ 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)
102
+ end
103
+ record
104
+ end
105
+
106
+ def set_inverse_instance_from_queries(record)
107
+ if inverse = inverse_association_for(record)
108
+ inverse.inversed_from_queries(owner)
111
109
  end
112
110
  record
113
111
  end
114
112
 
115
113
  # Remove the inverse association, if possible
116
114
  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
115
+ if inverse = inverse_association_for(record)
116
+ inverse.inversed_from(nil)
121
117
  end
122
118
  end
123
119
 
120
+ def inversed_from(record)
121
+ self.target = record
122
+ @inversed = !!record
123
+ end
124
+ alias :inversed_from_queries :inversed_from
125
+
124
126
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
125
127
  # polymorphic_type field on the owner.
126
128
  def klass
@@ -130,14 +132,14 @@ module ActiveRecord
130
132
  # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
131
133
  # through association's scope)
132
134
  def target_scope
133
- AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all)
135
+ AssociationRelation.create(klass, self).merge!(klass.all)
134
136
  end
135
137
 
136
138
  def extensions
137
139
  extensions = klass.default_extensions | reflection.extensions
138
140
 
139
- if scope = reflection.scope
140
- extensions |= klass.unscoped.instance_exec(owner, &scope).extensions
141
+ if reflection.scope
142
+ extensions |= reflection.scope_for(klass.unscoped, owner).extensions
141
143
  end
142
144
 
143
145
  extensions
@@ -162,17 +164,9 @@ module ActiveRecord
162
164
  reset
163
165
  end
164
166
 
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
167
+ # We can't dump @reflection and @through_reflection since it contains the scope proc
174
168
  def marshal_dump
175
- ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
169
+ ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
176
170
  [@reflection.name, ivars]
177
171
  end
178
172
 
@@ -187,8 +181,8 @@ module ActiveRecord
187
181
  skip_assign = [reflection.foreign_key, reflection.type].compact
188
182
  assigned_keys = record.changed_attribute_names_to_save
189
183
  assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
190
- attributes = create_scope.except(*(assigned_keys - skip_assign))
191
- record.assign_attributes(attributes)
184
+ attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
185
+ record.send(:_assign_attributes, attributes) if attributes.any?
192
186
  set_inverse_instance(record)
193
187
  end
194
188
 
@@ -201,6 +195,9 @@ module ActiveRecord
201
195
  end
202
196
 
203
197
  private
198
+ def scope_for_create
199
+ scope.scope_for_create
200
+ end
204
201
 
205
202
  def find_target?
206
203
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
@@ -212,8 +209,8 @@ module ActiveRecord
212
209
  if (reflection.has_one? || reflection.collection?) && !options[:through]
213
210
  attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
214
211
 
215
- if reflection.options[:as]
216
- attributes[reflection.type] = owner.class.base_class.name
212
+ if reflection.type
213
+ attributes[reflection.type] = owner.class.polymorphic_name
217
214
  end
218
215
  end
219
216
 
@@ -251,6 +248,12 @@ module ActiveRecord
251
248
  end
252
249
  end
253
250
 
251
+ def inverse_association_for(record)
252
+ if invertible_for?(record)
253
+ record.association(inverse_reflection_for(record).name)
254
+ end
255
+ end
256
+
254
257
  # Can be redefined by subclasses, notably polymorphic belongs_to
255
258
  # The record parameter is necessary to support polymorphic inverses as we must check for
256
259
  # the association in the specific class of the record.
@@ -280,11 +283,12 @@ module ActiveRecord
280
283
  def build_record(attributes)
281
284
  reflection.build_association(attributes) do |record|
282
285
  initialize_attributes(record, attributes)
286
+ yield(record) if block_given?
283
287
  end
284
288
  end
285
289
 
286
290
  # Returns true if statement cache should be skipped on the association reader.
287
- def skip_statement_cache?
291
+ def skip_statement_cache?(scope)
288
292
  reflection.has_scope? ||
289
293
  scope.eager_loading? ||
290
294
  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)
@@ -72,15 +91,15 @@ module ActiveRecord
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)