activerecord 5.1.7 → 5.2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  # = Active Record Attribute Methods Before Type Cast
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/module/attribute_accessors"
3
- require "active_record/attribute_mutation_tracker"
4
4
 
5
5
  module ActiveRecord
6
6
  module AttributeMethods
@@ -14,11 +14,7 @@ module ActiveRecord
14
14
  raise "You cannot include Dirty after Timestamp"
15
15
  end
16
16
 
17
- class_attribute :partial_writes, instance_writer: false
18
- self.partial_writes = true
19
-
20
- after_create { changes_internally_applied }
21
- after_update { changes_internally_applied }
17
+ class_attribute :partial_writes, instance_writer: false, default: true
22
18
 
23
19
  # Attribute methods for "changed in last call to save?"
24
20
  attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
@@ -30,107 +26,18 @@ module ActiveRecord
30
26
  attribute_method_suffix("_change_to_be_saved", "_in_database")
31
27
  end
32
28
 
33
- # Attempts to +save+ the record and clears changed attributes if successful.
34
- def save(*)
35
- if status = super
36
- changes_applied
37
- end
38
- status
39
- end
40
-
41
- # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
42
- def save!(*)
43
- super.tap do
44
- changes_applied
45
- end
46
- end
47
-
48
29
  # <tt>reload</tt> the record and clears changed attributes.
49
30
  def reload(*)
50
31
  super.tap do
51
- @previous_mutation_tracker = nil
52
- clear_mutation_trackers
53
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
54
- end
55
- end
56
-
57
- def initialize_dup(other) # :nodoc:
58
- super
59
- @attributes = self.class._default_attributes.map do |attr|
60
- attr.with_value_from_user(@attributes.fetch_value(attr.name))
61
- end
62
- clear_mutation_trackers
63
- end
64
-
65
- def changes_internally_applied # :nodoc:
66
- @mutations_before_last_save = mutations_from_database
67
- forget_attribute_assignments
68
- @mutations_from_database = AttributeMutationTracker.new(@attributes)
69
- end
70
-
71
- def changes_applied # :nodoc:
72
- @previous_mutation_tracker = mutation_tracker
73
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
74
- @mutation_tracker = nil
75
- @mutations_from_database = nil
76
- end
77
-
78
- def clear_changes_information # :nodoc:
79
- @previous_mutation_tracker = nil
80
- @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
81
- forget_attribute_assignments
82
- clear_mutation_trackers
83
- end
84
-
85
- def raw_write_attribute(attr_name, *) # :nodoc:
86
- result = super
87
- clear_attribute_change(attr_name)
88
- result
89
- end
90
-
91
- def clear_attribute_changes(attr_names) # :nodoc:
92
- super
93
- attr_names.each do |attr_name|
94
- clear_attribute_change(attr_name)
95
- end
96
- end
97
-
98
- def changed_attributes # :nodoc:
99
- # This should only be set by methods which will call changed_attributes
100
- # multiple times when it is known that the computed value cannot change.
101
- if defined?(@cached_changed_attributes)
102
- @cached_changed_attributes
103
- else
104
- emit_warning_if_needed("changed_attributes", "saved_changes.transform_values(&:first)")
105
- super.reverse_merge(mutation_tracker.changed_values).freeze
106
- end
107
- end
108
-
109
- def changes # :nodoc:
110
- cache_changed_attributes do
111
- emit_warning_if_needed("changes", "saved_changes")
112
- super
113
- end
114
- end
115
-
116
- def previous_changes # :nodoc:
117
- unless previous_mutation_tracker.equal?(mutations_before_last_save)
118
- ActiveSupport::Deprecation.warn(<<-EOW.strip_heredoc)
119
- The behavior of `previous_changes` inside of after callbacks is
120
- deprecated without replacement. In the next release of Rails,
121
- this method inside of `after_save` will return the changes that
122
- were just saved.
123
- EOW
32
+ @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
33
+ @mutations_before_last_save = nil
34
+ @attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
35
+ @mutations_from_database = nil
124
36
  end
125
- previous_mutation_tracker.changes
126
- end
127
-
128
- def attribute_changed_in_place?(attr_name) # :nodoc:
129
- mutation_tracker.changed_in_place?(attr_name)
130
37
  end
131
38
 
132
39
  # Did this attribute change when we last saved? This method can be invoked
133
- # as `saved_change_to_name?` instead of `saved_change_to_attribute?("name")`.
40
+ # as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
134
41
  # Behaves similarly to +attribute_changed?+. This method is useful in
135
42
  # after callbacks to determine if the call to save changed a certain
136
43
  # attribute.
@@ -153,8 +60,8 @@ module ActiveRecord
153
60
  # Behaves similarly to +attribute_change+. This method is useful in after
154
61
  # callbacks, to see the change in an attribute that just occurred
155
62
  #
156
- # This method can be invoked as `saved_change_to_name` in instead of
157
- # `saved_change_to_attribute("name")`
63
+ # This method can be invoked as +saved_change_to_name+ in instead of
64
+ # <tt>saved_change_to_attribute("name")</tt>
158
65
  def saved_change_to_attribute(attr_name)
159
66
  mutations_before_last_save.change_to_attribute(attr_name)
160
67
  end
@@ -167,7 +74,7 @@ module ActiveRecord
167
74
  mutations_before_last_save.original_value(attr_name)
168
75
  end
169
76
 
170
- # Did the last call to `save` have any changes to change?
77
+ # Did the last call to +save+ have any changes to change?
171
78
  def saved_changes?
172
79
  mutations_before_last_save.any_changes?
173
80
  end
@@ -177,158 +84,67 @@ module ActiveRecord
177
84
  mutations_before_last_save.changes
178
85
  end
179
86
 
180
- # Alias for `attribute_changed?`
87
+ # Alias for +attribute_changed?+
181
88
  def will_save_change_to_attribute?(attr_name, **options)
182
89
  mutations_from_database.changed?(attr_name, **options)
183
90
  end
184
91
 
185
- # Alias for `attribute_change`
92
+ # Alias for +attribute_change+
186
93
  def attribute_change_to_be_saved(attr_name)
187
94
  mutations_from_database.change_to_attribute(attr_name)
188
95
  end
189
96
 
190
- # Alias for `attribute_was`
97
+ # Alias for +attribute_was+
191
98
  def attribute_in_database(attr_name)
192
99
  mutations_from_database.original_value(attr_name)
193
100
  end
194
101
 
195
- # Alias for `changed?`
102
+ # Alias for +changed?+
196
103
  def has_changes_to_save?
197
104
  mutations_from_database.any_changes?
198
105
  end
199
106
 
200
- # Alias for `changes`
107
+ # Alias for +changes+
201
108
  def changes_to_save
202
109
  mutations_from_database.changes
203
110
  end
204
111
 
205
- # Alias for `changed`
112
+ # Alias for +changed+
206
113
  def changed_attribute_names_to_save
207
114
  mutations_from_database.changed_attribute_names
208
115
  end
209
116
 
210
- # Alias for `changed_attributes`
117
+ # Alias for +changed_attributes+
211
118
  def attributes_in_database
212
119
  mutations_from_database.changed_values
213
120
  end
214
121
 
215
- def attribute_was(*)
216
- emit_warning_if_needed("attribute_was", "attribute_before_last_save")
217
- super
218
- end
219
-
220
- def attribute_change(*)
221
- emit_warning_if_needed("attribute_change", "saved_change_to_attribute")
222
- super
223
- end
224
-
225
- def attribute_changed?(*)
226
- emit_warning_if_needed("attribute_changed?", "saved_change_to_attribute?")
227
- super
228
- end
229
-
230
- def changed?(*)
231
- emit_warning_if_needed("changed?", "saved_changes?")
232
- super
233
- end
234
-
235
- def changed(*)
236
- emit_warning_if_needed("changed", "saved_changes.keys")
237
- super
238
- end
239
-
240
122
  private
241
-
242
- def mutation_tracker
243
- unless defined?(@mutation_tracker)
244
- @mutation_tracker = nil
245
- end
246
- @mutation_tracker ||= AttributeMutationTracker.new(@attributes)
247
- end
248
-
249
- def emit_warning_if_needed(method_name, new_method_name)
250
- unless mutation_tracker.equal?(mutations_from_database)
251
- ActiveSupport::Deprecation.warn(<<-EOW.squish)
252
- The behavior of `#{method_name}` inside of after callbacks will
253
- be changing in the next version of Rails. The new return value will reflect the
254
- behavior of calling the method after `save` returned (e.g. the opposite of what
255
- it returns now). To maintain the current behavior, use `#{new_method_name}`
256
- instead.
257
- EOW
258
- end
259
- end
260
-
261
- def mutations_from_database
262
- unless defined?(@mutations_from_database)
263
- @mutations_from_database = nil
264
- end
265
- @mutations_from_database ||= mutation_tracker
266
- end
267
-
268
- def changes_include?(attr_name)
269
- super || mutation_tracker.changed?(attr_name)
270
- end
271
-
272
- def clear_attribute_change(attr_name)
273
- mutation_tracker.forget_change(attr_name)
274
- mutations_from_database.forget_change(attr_name)
275
- end
276
-
277
- def attribute_will_change!(attr_name)
278
- super
279
- if self.class.has_attribute?(attr_name)
280
- mutations_from_database.force_change(attr_name)
281
- else
282
- ActiveSupport::Deprecation.warn(<<-EOW.squish)
283
- #{attr_name} is not an attribute known to Active Record.
284
- This behavior is deprecated and will be removed in the next
285
- version of Rails. If you'd like #{attr_name} to be managed
286
- by Active Record, add `attribute :#{attr_name} to your class.
287
- EOW
288
- mutations_from_database.deprecated_force_change(attr_name)
123
+ def write_attribute_without_type_cast(attr_name, value)
124
+ name = attr_name.to_s
125
+ if self.class.attribute_alias?(name)
126
+ name = self.class.attribute_alias(name)
289
127
  end
128
+ result = super(name, value)
129
+ clear_attribute_change(name)
130
+ result
290
131
  end
291
132
 
292
133
  def _update_record(*)
293
- partial_writes? ? super(keys_for_partial_write) : super
134
+ affected_rows = partial_writes? ? super(keys_for_partial_write) : super
135
+ changes_applied
136
+ affected_rows
294
137
  end
295
138
 
296
139
  def _create_record(*)
297
- partial_writes? ? super(keys_for_partial_write) : super
140
+ id = partial_writes? ? super(keys_for_partial_write) : super
141
+ changes_applied
142
+ id
298
143
  end
299
144
 
300
145
  def keys_for_partial_write
301
146
  changed_attribute_names_to_save & self.class.column_names
302
147
  end
303
-
304
- def forget_attribute_assignments
305
- @attributes = @attributes.map(&:forgetting_assignment)
306
- end
307
-
308
- def clear_mutation_trackers
309
- @mutation_tracker = nil
310
- @mutations_from_database = nil
311
- @mutations_before_last_save = nil
312
- end
313
-
314
- def previous_mutation_tracker
315
- @previous_mutation_tracker ||= NullMutationTracker.instance
316
- end
317
-
318
- def mutations_before_last_save
319
- @mutations_before_last_save ||= previous_mutation_tracker
320
- end
321
-
322
- def cache_changed_attributes
323
- @cached_changed_attributes = changed_attributes
324
- yield
325
- ensure
326
- clear_changed_attributes_cache
327
- end
328
-
329
- def clear_changed_attributes_cache
330
- remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
331
- end
332
148
  end
333
149
  end
334
150
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
 
3
5
  module ActiveRecord
@@ -8,23 +10,22 @@ module ActiveRecord
8
10
  # Returns this record's primary key value wrapped in an array if one is
9
11
  # available.
10
12
  def to_key
11
- sync_with_transaction_state
12
13
  key = id
13
14
  [key] if key
14
15
  end
15
16
 
16
17
  # Returns the primary key value.
17
18
  def id
18
- if pk = self.class.primary_key
19
- sync_with_transaction_state
20
- _read_attribute(pk)
21
- end
19
+ sync_with_transaction_state
20
+ primary_key = self.class.primary_key
21
+ _read_attribute(primary_key) if primary_key
22
22
  end
23
23
 
24
24
  # Sets the primary key value.
25
25
  def id=(value)
26
26
  sync_with_transaction_state
27
- write_attribute(self.class.primary_key, value) if self.class.primary_key
27
+ primary_key = self.class.primary_key
28
+ _write_attribute(primary_key, value) if primary_key
28
29
  end
29
30
 
30
31
  # Queries the primary key value.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Query
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Read
4
6
  extend ActiveSupport::Concern
5
7
 
6
- module ClassMethods
8
+ module ClassMethods # :nodoc:
7
9
  private
8
10
 
9
11
  # We want to generate the methods via module_eval rather than
@@ -29,9 +31,11 @@ module ActiveRecord
29
31
  temp_method = "__temp__#{safe_name}"
30
32
 
31
33
  ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
34
+ sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
32
35
 
33
36
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
34
37
  def #{temp_method}
38
+ #{sync_with_transaction_state}
35
39
  name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
36
40
  _read_attribute(name) { |n| missing_attribute(n, caller) }
37
41
  end
@@ -54,7 +58,9 @@ module ActiveRecord
54
58
  attr_name.to_s
55
59
  end
56
60
 
57
- name = self.class.primary_key if name == "id".freeze && self.class.primary_key
61
+ primary_key = self.class.primary_key
62
+ name = primary_key if name == "id".freeze && primary_key
63
+ sync_with_transaction_state if name == primary_key
58
64
  _read_attribute(name, &block)
59
65
  end
60
66
 
@@ -63,7 +69,7 @@ module ActiveRecord
63
69
  if defined?(JRUBY_VERSION)
64
70
  # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
65
71
  # https://github.com/jruby/jruby/pull/2562
66
- def _read_attribute(attr_name, &block) # :nodoc
72
+ def _read_attribute(attr_name, &block) # :nodoc:
67
73
  @attributes.fetch_value(attr_name.to_s, &block)
68
74
  end
69
75
  else
@@ -1,8 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module Serialization
4
6
  extend ActiveSupport::Concern
5
7
 
8
+ class ColumnNotSerializableError < StandardError
9
+ def initialize(name, type)
10
+ super <<-EOS.strip_heredoc
11
+ Column `#{name}` of type #{type.class} does not support `serialize` feature.
12
+ Usually it means that you are trying to use `serialize`
13
+ on a column that already implements serialization natively.
14
+ EOS
15
+ end
16
+ end
17
+
6
18
  module ClassMethods
7
19
  # If you have an attribute that needs to be saved to the database as an
8
20
  # object, and retrieved as the same object, then specify the name of that
@@ -58,9 +70,20 @@ module ActiveRecord
58
70
  end
59
71
 
60
72
  decorate_attribute_type(attr_name, :serialize) do |type|
73
+ if type_incompatible_with_serialize?(type, class_name_or_coder)
74
+ raise ColumnNotSerializableError.new(attr_name, type)
75
+ end
76
+
61
77
  Type::Serialized.new(type, coder)
62
78
  end
63
79
  end
80
+
81
+ private
82
+
83
+ def type_incompatible_with_serialize?(type, class_name)
84
+ type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
85
+ type.respond_to?(:type_cast_array, true) && class_name == ::Array
86
+ end
64
87
  end
65
88
  end
66
89
  end