activerecord 4.2.11.3 → 5.0.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 (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  module ActiveRecord
4
2
  module NullRelation # :nodoc:
5
3
  def exec_queries
@@ -14,7 +12,7 @@ module ActiveRecord
14
12
  0
15
13
  end
16
14
 
17
- def update_all(_updates, _conditions = nil, _options = {})
15
+ def update_all(_updates)
18
16
  0
19
17
  end
20
18
 
@@ -30,10 +28,18 @@ module ActiveRecord
30
28
  true
31
29
  end
32
30
 
31
+ def none?
32
+ true
33
+ end
34
+
33
35
  def any?
34
36
  false
35
37
  end
36
38
 
39
+ def one?
40
+ false
41
+ end
42
+
37
43
  def many?
38
44
  false
39
45
  end
@@ -62,9 +68,7 @@ module ActiveRecord
62
68
  calculate :maximum, nil
63
69
  end
64
70
 
65
- def calculate(operation, _column_name, _options = {})
66
- # TODO: Remove _options argument as soon we remove support to
67
- # activerecord-deprecated_finders.
71
+ def calculate(operation, _column_name)
68
72
  if [:count, :sum, :size].include? operation
69
73
  group_values.any? ? Hash.new : 0
70
74
  elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
@@ -74,8 +78,12 @@ module ActiveRecord
74
78
  end
75
79
  end
76
80
 
77
- def exists?(_id = false)
81
+ def exists?(_conditions = :none)
78
82
  false
79
83
  end
84
+
85
+ def or(other)
86
+ other.spawn
87
+ end
80
88
  end
81
89
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
- # = Active Record Persistence
2
+ # = Active Record \Persistence
3
3
  module Persistence
4
4
  extend ActiveSupport::Concern
5
5
 
@@ -96,7 +96,8 @@ module ActiveRecord
96
96
  # Returns true if the record is persisted, i.e. it's not a new record and it was
97
97
  # not destroyed, otherwise returns false.
98
98
  def persisted?
99
- !(new_record? || destroyed?)
99
+ sync_with_transaction_state
100
+ !(@new_record || @destroyed)
100
101
  end
101
102
 
102
103
  # Saves the model.
@@ -105,41 +106,49 @@ module ActiveRecord
105
106
  # the existing record gets updated.
106
107
  #
107
108
  # By default, save always run validations. If any of them fail the action
108
- # is cancelled and +save+ returns +false+. However, if you supply
109
+ # is cancelled and #save returns +false+. However, if you supply
109
110
  # validate: false, validations are bypassed altogether. See
110
111
  # ActiveRecord::Validations for more information.
111
112
  #
112
- # There's a series of callbacks associated with +save+. If any of the
113
- # <tt>before_*</tt> callbacks return +false+ the action is cancelled and
114
- # +save+ returns +false+. See ActiveRecord::Callbacks for further
113
+ # By default, #save also sets the +updated_at+/+updated_on+ attributes to
114
+ # the current time. However, if you supply <tt>touch: false</tt>, these
115
+ # timestamps will not be updated.
116
+ #
117
+ # There's a series of callbacks associated with #save. If any of the
118
+ # <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled and
119
+ # #save returns +false+. See ActiveRecord::Callbacks for further
115
120
  # details.
116
121
  #
117
122
  # Attributes marked as readonly are silently ignored if the record is
118
123
  # being updated.
119
- def save(*)
120
- create_or_update
124
+ def save(*args)
125
+ create_or_update(*args)
121
126
  rescue ActiveRecord::RecordInvalid
122
127
  false
123
128
  end
124
129
 
125
130
  # Saves the model.
126
131
  #
127
- # If the model is new a record gets created in the database, otherwise
132
+ # If the model is new, a record gets created in the database, otherwise
128
133
  # the existing record gets updated.
129
134
  #
130
- # With <tt>save!</tt> validations always run. If any of them fail
135
+ # With #save! validations always run. If any of them fail
131
136
  # ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
132
137
  # for more information.
133
138
  #
134
- # There's a series of callbacks associated with <tt>save!</tt>. If any of
135
- # the <tt>before_*</tt> callbacks return +false+ the action is cancelled
136
- # and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
139
+ # By default, #save! also sets the +updated_at+/+updated_on+ attributes to
140
+ # the current time. However, if you supply <tt>touch: false</tt>, these
141
+ # timestamps will not be updated.
142
+ #
143
+ # There's a series of callbacks associated with #save!. If any of
144
+ # the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
145
+ # and #save! raises ActiveRecord::RecordNotSaved. See
137
146
  # ActiveRecord::Callbacks for further details.
138
147
  #
139
148
  # Attributes marked as readonly are silently ignored if the record is
140
149
  # being updated.
141
- def save!(*)
142
- create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
150
+ def save!(*args)
151
+ create_or_update(*args) || raise(RecordNotSaved.new("Failed to save the record", self))
143
152
  end
144
153
 
145
154
  # Deletes the record in the database and freezes this instance to
@@ -149,6 +158,8 @@ module ActiveRecord
149
158
  # The row is simply removed with an SQL +DELETE+ statement on the
150
159
  # record's primary key, and no callbacks are executed.
151
160
  #
161
+ # Note that this will also delete records marked as {#readonly?}[rdoc-ref:Core#readonly?].
162
+ #
152
163
  # To enforce the object's +before_destroy+ and +after_destroy+
153
164
  # callbacks or any <tt>:dependent</tt> association
154
165
  # options, use <tt>#destroy</tt>.
@@ -161,10 +172,10 @@ module ActiveRecord
161
172
  # Deletes the record in the database and freezes this instance to reflect
162
173
  # that no changes should be made (since they can't be persisted).
163
174
  #
164
- # There's a series of callbacks associated with <tt>destroy</tt>. If
165
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
166
- # and <tt>destroy</tt> returns +false+. See
167
- # ActiveRecord::Callbacks for further details.
175
+ # There's a series of callbacks associated with #destroy. If the
176
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
177
+ # and #destroy returns +false+.
178
+ # See ActiveRecord::Callbacks for further details.
168
179
  def destroy
169
180
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
170
181
  destroy_associations
@@ -177,12 +188,12 @@ module ActiveRecord
177
188
  # Deletes the record in the database and freezes this instance to reflect
178
189
  # that no changes should be made (since they can't be persisted).
179
190
  #
180
- # There's a series of callbacks associated with <tt>destroy!</tt>. If
181
- # the <tt>before_destroy</tt> callback return +false+ the action is cancelled
182
- # and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
183
- # ActiveRecord::Callbacks for further details.
191
+ # There's a series of callbacks associated with #destroy!. If the
192
+ # <tt>before_destroy</tt> callback throws +:abort+ the action is cancelled
193
+ # and #destroy! raises ActiveRecord::RecordNotDestroyed.
194
+ # See ActiveRecord::Callbacks for further details.
184
195
  def destroy!
185
- destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
196
+ destroy || _raise_record_not_destroyed
186
197
  end
187
198
 
188
199
  # Returns an instance of the specified +klass+ with the attributes of the
@@ -194,19 +205,21 @@ module ActiveRecord
194
205
  # instance using the companies/company partial instead of clients/client.
195
206
  #
196
207
  # Note: The new instance will share a link to the same attributes as the original class.
197
- # So any change to the attributes in either instance will affect the other.
208
+ # Therefore the sti column value will still be the same.
209
+ # Any change to the attributes on either instance will affect both instances.
210
+ # If you want to change the sti column as well, use #becomes! instead.
198
211
  def becomes(klass)
199
212
  became = klass.new
200
213
  became.instance_variable_set("@attributes", @attributes)
201
- changed_attributes = @changed_attributes if defined?(@changed_attributes)
202
- became.instance_variable_set("@changed_attributes", changed_attributes || {})
214
+ became.instance_variable_set("@mutation_tracker", @mutation_tracker) if defined?(@mutation_tracker)
215
+ became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
203
216
  became.instance_variable_set("@new_record", new_record?)
204
217
  became.instance_variable_set("@destroyed", destroyed?)
205
- became.instance_variable_set("@errors", errors)
218
+ became.errors.copy!(errors)
206
219
  became
207
220
  end
208
221
 
209
- # Wrapper around +becomes+ that also changes the instance's sti column value.
222
+ # Wrapper around #becomes that also changes the instance's sti column value.
210
223
  # This is especially useful if you want to persist the changed class in your
211
224
  # database.
212
225
  #
@@ -226,19 +239,19 @@ module ActiveRecord
226
239
  # This is especially useful for boolean flags on existing records. Also note that
227
240
  #
228
241
  # * Validation is skipped.
229
- # * Callbacks are invoked.
242
+ # * \Callbacks are invoked.
230
243
  # * updated_at/updated_on column is updated if that column is available.
231
244
  # * Updates all the attributes that are dirty in this object.
232
245
  #
233
- # This method raises an +ActiveRecord::ActiveRecordError+ if the
246
+ # This method raises an ActiveRecord::ActiveRecordError if the
234
247
  # attribute is marked as readonly.
235
248
  #
236
- # See also +update_column+.
249
+ # See also #update_column.
237
250
  def update_attribute(name, value)
238
251
  name = name.to_s
239
252
  verify_readonly_attribute(name)
240
- send("#{name}=", value)
241
- save(validate: false)
253
+ public_send("#{name}=", value)
254
+ save(validate: false) if changed?
242
255
  end
243
256
 
244
257
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -255,7 +268,7 @@ module ActiveRecord
255
268
 
256
269
  alias update_attributes update
257
270
 
258
- # Updates its receiver just like +update+ but calls <tt>save!</tt> instead
271
+ # Updates its receiver just like #update but calls #save! instead
259
272
  # of +save+, so an exception is raised if the record is invalid.
260
273
  def update!(attributes)
261
274
  # The following transaction covers any possible database side-effects of the
@@ -282,11 +295,12 @@ module ActiveRecord
282
295
  # the database, but take into account that in consequence the regular update
283
296
  # procedures are totally bypassed. In particular:
284
297
  #
285
- # * Validations are skipped.
286
- # * Callbacks are skipped.
298
+ # * \Validations are skipped.
299
+ # * \Callbacks are skipped.
287
300
  # * +updated_at+/+updated_on+ are not updated.
301
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
288
302
  #
289
- # This method raises an +ActiveRecord::ActiveRecordError+ when called on new
303
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
290
304
  # objects, or when at least one of the attributes is marked as readonly.
291
305
  def update_columns(attributes)
292
306
  raise ActiveRecordError, "cannot update a new record" if new_record?
@@ -314,41 +328,51 @@ module ActiveRecord
314
328
  self
315
329
  end
316
330
 
317
- # Wrapper around +increment+ that saves the record. This method differs from
331
+ # Wrapper around #increment that saves the record. This method differs from
318
332
  # its non-bang version in that it passes through the attribute setter.
319
333
  # Saving is not subjected to validation checks. Returns +true+ if the
320
334
  # record could be saved.
321
335
  def increment!(attribute, by = 1)
322
- increment(attribute, by).update_attribute(attribute, self[attribute])
336
+ increment(attribute, by)
337
+ change = public_send(attribute) - (attribute_was(attribute.to_s) || 0)
338
+ self.class.update_counters(id, attribute => change)
339
+ clear_attribute_change(attribute) # eww
340
+ self
323
341
  end
324
342
 
325
343
  # Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
326
344
  # The decrement is performed directly on the underlying attribute, no setter is invoked.
327
345
  # Only makes sense for number-based attributes. Returns +self+.
328
346
  def decrement(attribute, by = 1)
329
- self[attribute] ||= 0
330
- self[attribute] -= by
331
- self
347
+ increment(attribute, -by)
332
348
  end
333
349
 
334
- # Wrapper around +decrement+ that saves the record. This method differs from
350
+ # Wrapper around #decrement that saves the record. This method differs from
335
351
  # its non-bang version in that it passes through the attribute setter.
336
352
  # Saving is not subjected to validation checks. Returns +true+ if the
337
353
  # record could be saved.
338
354
  def decrement!(attribute, by = 1)
339
- decrement(attribute, by).update_attribute(attribute, self[attribute])
355
+ increment!(attribute, -by)
340
356
  end
341
357
 
342
358
  # Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
343
359
  # if the predicate returns +true+ the attribute will become +false+. This
344
360
  # method toggles directly the underlying value without calling any setter.
345
361
  # Returns +self+.
362
+ #
363
+ # Example:
364
+ #
365
+ # user = User.first
366
+ # user.banned? # => false
367
+ # user.toggle(:banned)
368
+ # user.banned? # => true
369
+ #
346
370
  def toggle(attribute)
347
- self[attribute] = !send("#{attribute}?")
371
+ self[attribute] = !public_send("#{attribute}?")
348
372
  self
349
373
  end
350
374
 
351
- # Wrapper around +toggle+ that saves the record. This method differs from
375
+ # Wrapper around #toggle that saves the record. This method differs from
352
376
  # its non-bang version in that it passes through the attribute setter.
353
377
  # Saving is not subjected to validation checks. Returns +true+ if the
354
378
  # record could be saved.
@@ -371,7 +395,7 @@ module ActiveRecord
371
395
  # Attributes are reloaded from the database, and caches busted, in
372
396
  # particular the associations cache and the QueryCache.
373
397
  #
374
- # If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
398
+ # If the record no longer exists in the database ActiveRecord::RecordNotFound
375
399
  # is raised. Otherwise, in addition to the in-place modification the method
376
400
  # returns +self+ for convenience.
377
401
  #
@@ -405,8 +429,6 @@ module ActiveRecord
405
429
  # end
406
430
  #
407
431
  def reload(options = nil)
408
- clear_aggregation_cache
409
- clear_association_cache
410
432
  self.class.connection.clear_query_cache
411
433
 
412
434
  fresh_object =
@@ -421,19 +443,22 @@ module ActiveRecord
421
443
  self
422
444
  end
423
445
 
424
- # Saves the record with the updated_at/on attributes set to the current time.
446
+ # Saves the record with the updated_at/on attributes set to the current time
447
+ # or the time specified.
425
448
  # Please note that no validation is performed and only the +after_touch+,
426
449
  # +after_commit+ and +after_rollback+ callbacks are executed.
427
450
  #
451
+ # This method can be passed attribute names and an optional time argument.
428
452
  # If attribute names are passed, they are updated along with updated_at/on
429
- # attributes.
453
+ # attributes. If no time argument is passed, the current time is used as default.
430
454
  #
431
- # product.touch # updates updated_at/on
455
+ # product.touch # updates updated_at/on with current time
456
+ # product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
432
457
  # product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
433
458
  # product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
434
459
  #
435
- # If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
436
- # associated object.
460
+ # If used along with {belongs_to}[rdoc-ref:Associations::ClassMethods#belongs_to]
461
+ # then +touch+ will invoke +touch+ method on associated object.
437
462
  #
438
463
  # class Brake < ActiveRecord::Base
439
464
  # belongs_to :car, touch: true
@@ -452,26 +477,38 @@ module ActiveRecord
452
477
  # ball = Ball.new
453
478
  # ball.touch(:updated_at) # => raises ActiveRecordError
454
479
  #
455
- def touch(*names)
480
+ def touch(*names, time: nil)
456
481
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
457
482
 
483
+ time ||= current_time_from_proper_timezone
458
484
  attributes = timestamp_attributes_for_update_in_model
459
485
  attributes.concat(names)
460
486
 
461
487
  unless attributes.empty?
462
- current_time = current_time_from_proper_timezone
463
488
  changes = {}
464
489
 
465
490
  attributes.each do |column|
466
491
  column = column.to_s
467
- changes[column] = write_attribute(column, current_time)
492
+ changes[column] = write_attribute(column, time)
468
493
  end
469
494
 
470
- changes[self.class.locking_column] = increment_lock if locking_enabled?
471
-
472
495
  clear_attribute_changes(changes.keys)
473
496
  primary_key = self.class.primary_key
474
- self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
497
+ scope = self.class.unscoped.where(primary_key => _read_attribute(primary_key))
498
+
499
+ if locking_enabled?
500
+ locking_column = self.class.locking_column
501
+ scope = scope.where(locking_column => _read_attribute(locking_column))
502
+ changes[locking_column] = increment_lock
503
+ end
504
+
505
+ result = scope.update_all(changes) == 1
506
+
507
+ if !result && locking_enabled?
508
+ raise ActiveRecord::StaleObjectError.new(self, "touch")
509
+ end
510
+
511
+ result
475
512
  else
476
513
  true
477
514
  end
@@ -488,20 +525,12 @@ module ActiveRecord
488
525
  end
489
526
 
490
527
  def relation_for_destroy
491
- pk = self.class.primary_key
492
- column = self.class.columns_hash[pk]
493
- substitute = self.class.connection.substitute_at(column)
494
-
495
- relation = self.class.unscoped.where(
496
- self.class.arel_table[pk].eq(substitute))
497
-
498
- relation.bind_values = [[column, id]]
499
- relation
528
+ self.class.unscoped.where(self.class.primary_key => id)
500
529
  end
501
530
 
502
- def create_or_update
531
+ def create_or_update(*args)
503
532
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
504
- result = new_record? ? _create_record : _update_record
533
+ result = new_record? ? _create_record : _update_record(*args)
505
534
  result != false
506
535
  end
507
536
 
@@ -531,5 +560,16 @@ module ActiveRecord
531
560
  def verify_readonly_attribute(name)
532
561
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
533
562
  end
563
+
564
+ def _raise_record_not_destroyed
565
+ @_association_destroy_exception ||= nil
566
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
567
+ ensure
568
+ @_association_destroy_exception = nil
569
+ end
570
+
571
+ def belongs_to_touch_method
572
+ :touch
573
+ end
534
574
  end
535
575
  end
@@ -6,8 +6,8 @@ module ActiveRecord
6
6
  delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
7
7
  delegate :find_by, :find_by!, to: :all
8
8
  delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all
9
- delegate :find_each, :find_in_batches, to: :all
10
- delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
9
+ delegate :find_each, :find_in_batches, :in_batches, to: :all
10
+ delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
11
11
  :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
12
12
  :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all
13
13
  delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
@@ -55,11 +55,12 @@ module ActiveRecord
55
55
  # The use of this method should be restricted to complicated SQL queries that can't be executed
56
56
  # using the ActiveRecord::Calculations class methods. Look into those before using this.
57
57
  #
58
- # ==== Parameters
58
+ # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
59
+ # # => 12
59
60
  #
60
- # * +sql+ - An SQL statement which should return a count query from the database, see the example below.
61
+ # ==== Parameters
61
62
  #
62
- # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
63
+ # * +sql+ - An SQL statement which should return a count query from the database, see the example above.
63
64
  def count_by_sql(sql)
64
65
  sql = sanitize_conditions(sql)
65
66
  connection.select_value(sql, "#{name} Count").to_i