activerecord 5.0.7.2 → 5.1.0.beta1

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 (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/string/conversions'
1
+ require "active_support/core_ext/string/conversions"
2
2
 
3
3
  module ActiveRecord
4
4
  module Associations
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/array/wrap'
1
+ require "active_support/core_ext/array/wrap"
2
2
 
3
3
  module ActiveRecord
4
4
  module Associations
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  attr_reader :owner, :target, :reflection
20
20
  attr_accessor :inversed
21
21
 
22
- delegate :options, :to => :reflection
22
+ delegate :options, to: :reflection
23
23
 
24
24
  def initialize(owner, reflection)
25
25
  reflection.check_validity!
@@ -112,6 +112,15 @@ module ActiveRecord
112
112
  record
113
113
  end
114
114
 
115
+ # Remove the inverse association, if possible
116
+ 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
121
+ end
122
+ end
123
+
115
124
  # Returns the class of the target. belongs_to polymorphic overrides this to look at the
116
125
  # polymorphic_type field on the owner.
117
126
  def klass
@@ -124,16 +133,6 @@ module ActiveRecord
124
133
  AssociationRelation.create(klass, klass.arel_table, klass.predicate_builder, self).merge!(klass.all)
125
134
  end
126
135
 
127
- def extensions
128
- extensions = klass.default_extensions | reflection.extensions
129
-
130
- if scope = reflection.scope
131
- extensions |= klass.unscoped.instance_exec(owner, &scope).extensions
132
- end
133
-
134
- extensions
135
- end
136
-
137
136
  # Loads the \target if needed and returns it.
138
137
  #
139
138
  # This method is abstract in the sense that it relies on +find_target+,
@@ -176,13 +175,21 @@ module ActiveRecord
176
175
  def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
177
176
  except_from_scope_attributes ||= {}
178
177
  skip_assign = [reflection.foreign_key, reflection.type].compact
179
- assigned_keys = record.changed
178
+ assigned_keys = record.changed_attribute_names_to_save
180
179
  assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
181
180
  attributes = create_scope.except(*(assigned_keys - skip_assign))
182
181
  record.assign_attributes(attributes)
183
182
  set_inverse_instance(record)
184
183
  end
185
184
 
185
+ def create(attributes = {}, &block)
186
+ _create_record(attributes, &block)
187
+ end
188
+
189
+ def create!(attributes = {}, &block)
190
+ _create_record(attributes, true, &block)
191
+ end
192
+
186
193
  private
187
194
 
188
195
  def find_target?
@@ -227,7 +234,8 @@ module ActiveRecord
227
234
  unless record.is_a?(reflection.klass)
228
235
  fresh_class = reflection.class_name.safe_constantize
229
236
  unless fresh_class && record.is_a?(fresh_class)
230
- message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
237
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
238
+ "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
231
239
  raise ActiveRecord::AssociationTypeMismatch, message
232
240
  end
233
241
  end
@@ -255,7 +263,7 @@ module ActiveRecord
255
263
  # so that when stale_state is different from the value stored on the last find_target,
256
264
  # the target is stale.
257
265
  #
258
- # This is only relevant to certain associations, which is why it returns nil by default.
266
+ # This is only relevant to certain associations, which is why it returns +nil+ by default.
259
267
  def stale_state
260
268
  end
261
269
 
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
  alias_tracker = AliasTracker.create connection, association.klass.table_name, klass.type_caster
25
25
  chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
26
26
 
27
- scope.extending! reflection.extensions
27
+ scope.extending! Array(reflection.options[:extend])
28
28
  add_constraints(scope, owner, klass, reflection, chain_head, chain_tail)
29
29
  end
30
30
 
@@ -49,118 +49,120 @@ module ActiveRecord
49
49
  binds
50
50
  end
51
51
 
52
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
53
+ # Workaround for Ruby 2.2 "private attribute?" warning.
52
54
  protected
53
55
 
54
- attr_reader :value_transformation
56
+ attr_reader :value_transformation
55
57
 
56
58
  private
57
- def join(table, constraint)
58
- table.create_join(table, table.create_on(constraint), join_type)
59
- end
59
+ def join(table, constraint)
60
+ table.create_join(table, table.create_on(constraint), join_type)
61
+ end
60
62
 
61
- def last_chain_scope(scope, table, reflection, owner, association_klass)
62
- join_keys = reflection.join_keys(association_klass)
63
- key = join_keys.key
64
- foreign_key = join_keys.foreign_key
63
+ def last_chain_scope(scope, table, reflection, owner, association_klass)
64
+ join_keys = reflection.join_keys(association_klass)
65
+ key = join_keys.key
66
+ foreign_key = join_keys.foreign_key
65
67
 
66
- value = transform_value(owner[foreign_key])
67
- scope = scope.where(table.name => { key => value })
68
+ value = transform_value(owner[foreign_key])
69
+ scope = scope.where(table.name => { key => value })
68
70
 
69
- if reflection.type
70
- polymorphic_type = transform_value(owner.class.base_class.name)
71
- scope = scope.where(table.name => { reflection.type => polymorphic_type })
71
+ if reflection.type
72
+ polymorphic_type = transform_value(owner.class.base_class.name)
73
+ scope = scope.where(table.name => { reflection.type => polymorphic_type })
74
+ end
75
+
76
+ scope
72
77
  end
73
78
 
74
- scope
75
- end
79
+ def transform_value(value)
80
+ value_transformation.call(value)
81
+ end
76
82
 
77
- def transform_value(value)
78
- value_transformation.call(value)
79
- end
83
+ def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
84
+ join_keys = reflection.join_keys(association_klass)
85
+ key = join_keys.key
86
+ foreign_key = join_keys.foreign_key
80
87
 
81
- def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
82
- join_keys = reflection.join_keys(association_klass)
83
- key = join_keys.key
84
- foreign_key = join_keys.foreign_key
88
+ constraint = table[key].eq(foreign_table[foreign_key])
85
89
 
86
- constraint = table[key].eq(foreign_table[foreign_key])
90
+ if reflection.type
91
+ value = transform_value(next_reflection.klass.base_class.name)
92
+ scope = scope.where(table.name => { reflection.type => value })
93
+ end
87
94
 
88
- if reflection.type
89
- value = transform_value(next_reflection.klass.base_class.name)
90
- scope = scope.where(table.name => { reflection.type => value })
95
+ scope = scope.joins(join(foreign_table, constraint))
91
96
  end
92
97
 
93
- scope = scope.joins(join(foreign_table, constraint))
94
- end
98
+ class ReflectionProxy < SimpleDelegator # :nodoc:
99
+ attr_accessor :next
100
+ attr_reader :alias_name
95
101
 
96
- class ReflectionProxy < SimpleDelegator # :nodoc:
97
- attr_accessor :next
98
- attr_reader :alias_name
102
+ def initialize(reflection, alias_name)
103
+ super(reflection)
104
+ @alias_name = alias_name
105
+ end
99
106
 
100
- def initialize(reflection, alias_name)
101
- super(reflection)
102
- @alias_name = alias_name
107
+ def all_includes; nil; end
103
108
  end
104
109
 
105
- def all_includes; nil; end
106
- end
107
-
108
- def get_chain(reflection, association, tracker)
109
- name = reflection.name
110
- runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
111
- previous_reflection = runtime_reflection
112
- reflection.chain.drop(1).each do |refl|
113
- alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name))
114
- proxy = ReflectionProxy.new(refl, alias_name)
115
- previous_reflection.next = proxy
116
- previous_reflection = proxy
110
+ def get_chain(reflection, association, tracker)
111
+ name = reflection.name
112
+ runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
113
+ previous_reflection = runtime_reflection
114
+ reflection.chain.drop(1).each do |refl|
115
+ alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name))
116
+ proxy = ReflectionProxy.new(refl, alias_name)
117
+ previous_reflection.next = proxy
118
+ previous_reflection = proxy
119
+ end
120
+ [runtime_reflection, previous_reflection]
117
121
  end
118
- [runtime_reflection, previous_reflection]
119
- end
120
-
121
- def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
122
- owner_reflection = chain_tail
123
- table = owner_reflection.alias_name
124
- scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
125
122
 
126
- reflection = chain_head
127
- loop do
128
- break unless reflection
129
- table = reflection.alias_name
123
+ def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
124
+ owner_reflection = chain_tail
125
+ table = owner_reflection.alias_name
126
+ scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
130
127
 
131
- unless reflection == chain_tail
128
+ reflection = chain_head
129
+ while reflection
130
+ table = reflection.alias_name
132
131
  next_reflection = reflection.next
133
- foreign_table = next_reflection.alias_name
134
- scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
135
- end
136
-
137
- # Exclude the scope of the association itself, because that
138
- # was already merged in the #scope method.
139
- reflection.constraints.each do |scope_chain_item|
140
- item = eval_scope(reflection.klass, scope_chain_item, owner)
141
132
 
142
- if scope_chain_item == refl.scope
143
- scope.merge! item.except(:where, :includes)
133
+ unless reflection == chain_tail
134
+ foreign_table = next_reflection.alias_name
135
+ scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
144
136
  end
145
137
 
146
- reflection.all_includes do
147
- scope.includes! item.includes_values
138
+ # Exclude the scope of the association itself, because that
139
+ # was already merged in the #scope method.
140
+ reflection.constraints.each do |scope_chain_item|
141
+ item = eval_scope(reflection.klass, table, scope_chain_item, owner)
142
+
143
+ if scope_chain_item == refl.scope
144
+ scope.merge! item.except(:where, :includes)
145
+ end
146
+
147
+ reflection.all_includes do
148
+ scope.includes! item.includes_values
149
+ end
150
+
151
+ scope.unscope!(*item.unscope_values)
152
+ scope.where_clause += item.where_clause
153
+ scope.order_values |= item.order_values
148
154
  end
149
155
 
150
- scope.unscope!(*item.unscope_values)
151
- scope.where_clause += item.where_clause
152
- scope.order_values |= item.order_values
156
+ reflection = next_reflection
153
157
  end
154
158
 
155
- reflection = reflection.next
159
+ scope
156
160
  end
157
161
 
158
- scope
159
- end
160
-
161
- def eval_scope(klass, scope, owner)
162
- klass.unscoped.instance_exec(owner, &scope)
163
- end
162
+ def eval_scope(klass, table, scope, owner)
163
+ predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
164
+ ActiveRecord::Relation.create(klass, table, predicate_builder).instance_exec(owner, &scope)
165
+ end
164
166
  end
165
167
  end
166
168
  end
@@ -2,7 +2,6 @@ module ActiveRecord
2
2
  # = Active Record Belongs To Association
3
3
  module Associations
4
4
  class BelongsToAssociation < SingularAssociation #:nodoc:
5
-
6
5
  def handle_dependency
7
6
  target.send(options[:dependent]) if load_target
8
7
  end
@@ -35,17 +35,17 @@ module ActiveRecord::Associations::Builder # :nodoc:
35
35
  @_after_create_counter_called = false
36
36
  elsif (@_after_replace_counter_called ||= false)
37
37
  @_after_replace_counter_called = false
38
- elsif attribute_changed?(foreign_key) && !new_record?
38
+ elsif saved_change_to_attribute?(foreign_key) && !new_record?
39
39
  if reflection.polymorphic?
40
- model = attribute(reflection.foreign_type).try(:constantize)
41
- model_was = attribute_was(reflection.foreign_type).try(:constantize)
40
+ model = attribute_in_database(reflection.foreign_type).try(:constantize)
41
+ model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
42
42
  else
43
43
  model = reflection.klass
44
44
  model_was = reflection.klass
45
45
  end
46
46
 
47
- foreign_key_was = attribute_was foreign_key
48
- foreign_key = attribute foreign_key
47
+ foreign_key_was = attribute_before_last_save foreign_key
48
+ foreign_key = attribute_in_database foreign_key
49
49
 
50
50
  if foreign_key && model.respond_to?(:increment_counter)
51
51
  model.increment_counter(cache_column, foreign_key)
@@ -70,14 +70,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
70
70
  klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
71
71
  end
72
72
 
73
- def self.touch_record(o, foreign_key, name, touch, touch_method) # :nodoc:
74
- old_foreign_id = o.changed_attributes[foreign_key]
73
+ def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc:
74
+ old_foreign_id = changes[foreign_key] && changes[foreign_key].first
75
75
 
76
76
  if old_foreign_id
77
77
  association = o.association(name)
78
78
  reflection = association.reflection
79
79
  if reflection.polymorphic?
80
- klass = o.public_send("#{reflection.foreign_type}_was").constantize
80
+ foreign_type = reflection.foreign_type
81
+ klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
82
+ klass = klass.constantize
81
83
  else
82
84
  klass = association.klass
83
85
  end
@@ -107,13 +109,13 @@ module ActiveRecord::Associations::Builder # :nodoc:
107
109
  n = reflection.name
108
110
  touch = reflection.options[:touch]
109
111
 
110
- callback = lambda { |record|
111
- BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
112
- }
112
+ callback = lambda { |changes_method| lambda { |record|
113
+ BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
114
+ }}
113
115
 
114
- model.after_save callback, if: :changed?
115
- model.after_touch callback
116
- model.after_destroy callback
116
+ model.after_save callback.(:saved_changes), if: :saved_changes?
117
+ model.after_touch callback.(:changes_to_save)
118
+ model.after_destroy callback.(:changes_to_save)
117
119
  end
118
120
 
119
121
  def self.add_destroy_callbacks(model, reflection)
@@ -1,10 +1,9 @@
1
1
  # This class is inherited by the has_many and has_many_and_belongs_to_many association classes
2
2
 
3
- require 'active_record/associations'
3
+ require "active_record/associations"
4
4
 
5
5
  module ActiveRecord::Associations::Builder # :nodoc:
6
6
  class CollectionAssociation < Association #:nodoc:
7
-
8
7
  CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
9
8
 
10
9
  def self.valid_options(options)
@@ -16,9 +16,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
16
16
 
17
17
  private
18
18
 
19
- def klass
20
- @lhs_class.send(:compute_type, @rhs_class_name)
21
- end
19
+ def klass
20
+ @lhs_class.send(:compute_type, @rhs_class_name)
21
+ end
22
22
  end
23
23
 
24
24
  def self.build(lhs_class, name, options)
@@ -28,7 +28,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
28
28
  class_name = options.fetch(:class_name) {
29
29
  name.to_s.camelize.singularize
30
30
  }
31
- KnownClass.new lhs_class, class_name
31
+ KnownClass.new lhs_class, class_name.to_s
32
32
  end
33
33
  end
34
34
  end
@@ -78,9 +78,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
78
78
 
79
79
  private
80
80
 
81
- def self.suppress_composite_primary_key(pk)
82
- pk unless pk.is_a?(Array)
83
- end
81
+ def self.suppress_composite_primary_key(pk)
82
+ pk unless pk.is_a?(Array)
83
+ end
84
84
  }
85
85
 
86
86
  join_model.name = "HABTM_#{association_name.to_s.camelize}"
@@ -94,7 +94,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
94
94
 
95
95
  def middle_reflection(join_model)
96
96
  middle_name = [lhs_model.name.downcase.pluralize,
97
- association_name].join('_'.freeze).gsub('::'.freeze, '_'.freeze).to_sym
97
+ association_name].join("_".freeze).gsub("::".freeze, "_".freeze).to_sym
98
98
  middle_options = middle_options join_model
99
99
 
100
100
  HasMany.create_reflection(lhs_model,
@@ -105,29 +105,29 @@ module ActiveRecord::Associations::Builder # :nodoc:
105
105
 
106
106
  private
107
107
 
108
- def middle_options(join_model)
109
- middle_options = {}
110
- middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
111
- middle_options[:source] = join_model.left_reflection.name
112
- if options.key? :foreign_key
113
- middle_options[:foreign_key] = options[:foreign_key]
108
+ def middle_options(join_model)
109
+ middle_options = {}
110
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
111
+ middle_options[:source] = join_model.left_reflection.name
112
+ if options.key? :foreign_key
113
+ middle_options[:foreign_key] = options[:foreign_key]
114
+ end
115
+ middle_options
114
116
  end
115
- middle_options
116
- end
117
117
 
118
- def belongs_to_options(options)
119
- rhs_options = {}
118
+ def belongs_to_options(options)
119
+ rhs_options = {}
120
120
 
121
- if options.key? :class_name
122
- rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
123
- rhs_options[:class_name] = options[:class_name]
124
- end
121
+ if options.key? :class_name
122
+ rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
123
+ rhs_options[:class_name] = options[:class_name]
124
+ end
125
125
 
126
- if options.key? :association_foreign_key
127
- rhs_options[:foreign_key] = options[:association_foreign_key]
128
- end
126
+ if options.key? :association_foreign_key
127
+ rhs_options[:foreign_key] = options[:association_foreign_key]
128
+ end
129
129
 
130
- rhs_options
131
- end
130
+ rhs_options
131
+ end
132
132
  end
133
133
  end