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
@@ -2,7 +2,6 @@ module ActiveRecord
2
2
  module Associations
3
3
  class Preloader
4
4
  class HasMany < CollectionAssociation #:nodoc:
5
-
6
5
  def association_key_name
7
6
  reflection.foreign_key
8
7
  end
@@ -10,7 +9,6 @@ module ActiveRecord
10
9
  def owner_key_name
11
10
  reflection.active_record_primary_key
12
11
  end
13
-
14
12
  end
15
13
  end
16
14
  end
@@ -2,18 +2,16 @@ module ActiveRecord
2
2
  module Associations
3
3
  class Preloader
4
4
  class SingularAssociation < Association #:nodoc:
5
-
6
5
  private
7
6
 
8
- def preload(preloader)
9
- associated_records_by_owner(preloader).each do |owner, associated_records|
10
- record = associated_records.first
7
+ def preload(preloader)
8
+ associated_records_by_owner(preloader).each do |owner, associated_records|
9
+ record = associated_records.first
11
10
 
12
- association = owner.association(reflection.name)
13
- association.target = record
11
+ association = owner.association(reflection.name)
12
+ association.target = record
13
+ end
14
14
  end
15
- end
16
-
17
15
  end
18
16
  end
19
17
  end
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
 
25
25
  reset_association owners, through_reflection.name
26
26
 
27
- middle_records = through_records.flat_map { |(_,rec)| rec }
27
+ middle_records = through_records.flat_map { |(_, rec)| rec }
28
28
 
29
29
  preloaders = preloader.preload(middle_records,
30
30
  source_reflection.name,
@@ -32,13 +32,13 @@ module ActiveRecord
32
32
 
33
33
  @preloaded_records = preloaders.flat_map(&:preloaded_records)
34
34
 
35
- middle_to_pl = preloaders.each_with_object({}) do |pl,h|
35
+ middle_to_pl = preloaders.each_with_object({}) do |pl, h|
36
36
  pl.owners.each { |middle|
37
37
  h[middle] = pl
38
38
  }
39
39
  end
40
40
 
41
- through_records.each_with_object({}) do |(lhs,center), records_by_owner|
41
+ through_records.each_with_object({}) do |(lhs, center), records_by_owner|
42
42
  pl_to_middle = center.group_by { |record| middle_to_pl[record] }
43
43
 
44
44
  records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
@@ -61,54 +61,47 @@ module ActiveRecord
61
61
 
62
62
  private
63
63
 
64
- def id_to_index_map(ids)
65
- id_map = {}
66
- ids.each_with_index { |id, index| id_map[id] = index }
67
- id_map
68
- end
64
+ def id_to_index_map(ids)
65
+ id_map = {}
66
+ ids.each_with_index { |id, index| id_map[id] = index }
67
+ id_map
68
+ end
69
69
 
70
- def reset_association(owners, association_name)
71
- should_reset = (through_scope != through_reflection.klass.unscoped) ||
72
- (reflection.options[:source_type] && through_reflection.collection?)
70
+ def reset_association(owners, association_name)
71
+ should_reset = (through_scope != through_reflection.klass.unscoped) ||
72
+ (reflection.options[:source_type] && through_reflection.collection?)
73
73
 
74
- # Don't cache the association - we would only be caching a subset
75
- if should_reset
76
- owners.each { |owner|
77
- owner.association(association_name).reset
78
- }
74
+ # Don't cache the association - we would only be caching a subset
75
+ if should_reset
76
+ owners.each { |owner|
77
+ owner.association(association_name).reset
78
+ }
79
+ end
79
80
  end
80
- end
81
81
 
82
- def through_scope
83
- scope = through_reflection.klass.unscoped
84
- values = reflection_scope.values
85
-
86
- if options[:source_type]
87
- scope.where! reflection.foreign_type => options[:source_type]
88
- else
89
- unless reflection_scope.where_clause.empty?
90
- scope.includes_values = Array(values[:includes] || options[:source])
91
- scope.where_clause = reflection_scope.where_clause
92
- if joins = values[:joins]
93
- scope.joins!(source_reflection.name => joins)
82
+ def through_scope
83
+ scope = through_reflection.klass.unscoped
84
+
85
+ if options[:source_type]
86
+ scope.where! reflection.foreign_type => options[:source_type]
87
+ else
88
+ unless reflection_scope.where_clause.empty?
89
+ scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
90
+ scope.where_clause = reflection_scope.where_clause
94
91
  end
95
- if left_outer_joins = values[:left_outer_joins]
96
- scope.left_outer_joins!(source_reflection.name => left_outer_joins)
92
+
93
+ scope.references! reflection_scope.values[:references]
94
+ if scope.eager_loading? && order_values = reflection_scope.values[:order]
95
+ scope = scope.order(order_values)
97
96
  end
98
97
  end
99
98
 
100
- scope.references! values[:references]
101
- if scope.eager_loading? && order_values = values[:order]
102
- scope = scope.order(order_values)
103
- end
99
+ scope
104
100
  end
105
101
 
106
- scope
107
- end
108
-
109
- def target_records_from_association(association)
110
- association.loaded? ? association.target : association.reader
111
- end
102
+ def target_records_from_association(association)
103
+ association.loaded? ? association.target : association.reader
104
+ end
112
105
  end
113
106
  end
114
107
  end
@@ -2,15 +2,8 @@ module ActiveRecord
2
2
  module Associations
3
3
  class SingularAssociation < Association #:nodoc:
4
4
  # Implements the reader method, e.g. foo.bar for Foo.has_one :bar
5
- def reader(force_reload = false)
6
- if force_reload && klass
7
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
8
- Passing an argument to force an association to reload is now
9
- deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
10
- MSG
11
-
12
- klass.uncached { reload }
13
- elsif !loaded? || stale_target?
5
+ def reader
6
+ if !loaded? || stale_target?
14
7
  reload
15
8
  end
16
9
 
@@ -22,14 +15,6 @@ module ActiveRecord
22
15
  replace(record)
23
16
  end
24
17
 
25
- def create(attributes = {}, &block)
26
- _create_record(attributes, &block)
27
- end
28
-
29
- def create!(attributes = {}, &block)
30
- _create_record(attributes, true, &block)
31
- end
32
-
33
18
  def build(attributes = {})
34
19
  record = build_record(attributes)
35
20
  yield(record) if block_given?
@@ -50,8 +35,8 @@ module ActiveRecord
50
35
  scope.scope_for_create.stringify_keys.except(klass.primary_key)
51
36
  end
52
37
 
53
- def get_records
54
- return scope.limit(1).records if skip_statement_cache?
38
+ def find_target
39
+ return scope.take if skip_statement_cache?
55
40
 
56
41
  conn = klass.connection
57
42
  sc = reflection.association_scope_cache(conn, owner) do
@@ -62,13 +47,11 @@ module ActiveRecord
62
47
  end
63
48
 
64
49
  binds = AssociationScope.get_bind_values(owner, reflection.chain)
65
- sc.execute binds, klass, klass.connection
66
- end
67
-
68
- def find_target
69
- if record = get_records.first
50
+ sc.execute(binds, klass, conn) do |record|
70
51
  set_inverse_instance record
71
- end
52
+ end.first
53
+ rescue ::RangeError
54
+ nil
72
55
  end
73
56
 
74
57
  def replace(record)
@@ -2,10 +2,9 @@ module ActiveRecord
2
2
  # = Active Record Through Association
3
3
  module Associations
4
4
  module ThroughAssociation #:nodoc:
5
+ delegate :source_reflection, :through_reflection, to: :reflection
5
6
 
6
- delegate :source_reflection, :through_reflection, :to => :reflection
7
-
8
- protected
7
+ private
9
8
 
10
9
  # We merge in these scopes for two reasons:
11
10
  #
@@ -14,7 +13,7 @@ module ActiveRecord
14
13
  def target_scope
15
14
  scope = super
16
15
  reflection.chain.drop(1).each do |reflection|
17
- relation = reflection.klass.scope_for_association
16
+ relation = reflection.klass.all
18
17
  scope.merge!(
19
18
  relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
20
19
  )
@@ -22,8 +21,6 @@ module ActiveRecord
22
21
  scope
23
22
  end
24
23
 
25
- private
26
-
27
24
  # Construct attributes for :through pointing to owner and associate. This is used by the
28
25
  # methods which create and delete records on the association.
29
26
  #
@@ -77,7 +77,11 @@ module ActiveRecord
77
77
  end
78
78
 
79
79
  def with_type(type)
80
- self.class.new(name, value_before_type_cast, type, original_attribute)
80
+ if changed_in_place?
81
+ with_value_from_user(value).with_type(type)
82
+ else
83
+ self.class.new(name, value_before_type_cast, type, original_attribute)
84
+ end
81
85
  end
82
86
 
83
87
  def type_cast(*)
@@ -108,106 +112,129 @@ module ActiveRecord
108
112
  [self.class, name, value_before_type_cast, type].hash
109
113
  end
110
114
 
111
- protected
112
-
113
- attr_reader :original_attribute
114
- alias_method :assigned?, :original_attribute
115
-
116
- def initialize_dup(other)
117
- if defined?(@value) && @value.duplicable?
118
- @value = @value.dup
119
- end
115
+ def init_with(coder)
116
+ @name = coder["name"]
117
+ @value_before_type_cast = coder["value_before_type_cast"]
118
+ @type = coder["type"]
119
+ @original_attribute = coder["original_attribute"]
120
+ @value = coder["value"] if coder.map.key?("value")
120
121
  end
121
122
 
122
- def changed_from_assignment?
123
- assigned? && type.changed?(original_value, value, value_before_type_cast)
123
+ def encode_with(coder)
124
+ coder["name"] = name
125
+ coder["value_before_type_cast"] = value_before_type_cast if value_before_type_cast
126
+ coder["type"] = type if type
127
+ coder["original_attribute"] = original_attribute if original_attribute
128
+ coder["value"] = value if defined?(@value)
124
129
  end
125
130
 
126
- def original_value_for_database
127
- if assigned?
128
- original_attribute.original_value_for_database
129
- else
130
- _original_value_for_database
131
- end
132
- end
131
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
132
+ # Workaround for Ruby 2.2 "private attribute?" warning.
133
+ protected
133
134
 
134
- def _original_value_for_database
135
- type.serialize(original_value)
136
- end
135
+ attr_reader :original_attribute
136
+ alias_method :assigned?, :original_attribute
137
137
 
138
- class FromDatabase < Attribute # :nodoc:
139
- def type_cast(value)
140
- type.deserialize(value)
138
+ def original_value_for_database
139
+ if assigned?
140
+ original_attribute.original_value_for_database
141
+ else
142
+ _original_value_for_database
143
+ end
141
144
  end
142
145
 
143
- def _original_value_for_database
144
- value_before_type_cast
146
+ private
147
+ def initialize_dup(other)
148
+ if defined?(@value) && @value.duplicable?
149
+ @value = @value.dup
150
+ end
145
151
  end
146
- end
147
152
 
148
- class FromUser < Attribute # :nodoc:
149
- def type_cast(value)
150
- type.cast(value)
153
+ def changed_from_assignment?
154
+ assigned? && type.changed?(original_value, value, value_before_type_cast)
151
155
  end
152
156
 
153
- def came_from_user?
154
- true
157
+ def _original_value_for_database
158
+ type.serialize(original_value)
155
159
  end
156
- end
157
160
 
158
- class WithCastValue < Attribute # :nodoc:
159
- def type_cast(value)
160
- value
161
- end
161
+ class FromDatabase < Attribute # :nodoc:
162
+ def type_cast(value)
163
+ type.deserialize(value)
164
+ end
162
165
 
163
- def changed_in_place?
164
- false
166
+ def _original_value_for_database
167
+ value_before_type_cast
168
+ end
165
169
  end
166
- end
167
170
 
168
- class Null < Attribute # :nodoc:
169
- def initialize(name)
170
- super(name, nil, Type::Value.new)
171
- end
171
+ class FromUser < Attribute # :nodoc:
172
+ def type_cast(value)
173
+ type.cast(value)
174
+ end
172
175
 
173
- def type_cast(*)
174
- nil
176
+ def came_from_user?
177
+ true
178
+ end
175
179
  end
176
180
 
177
- def with_type(type)
178
- self.class.with_cast_value(name, nil, type)
179
- end
181
+ class WithCastValue < Attribute # :nodoc:
182
+ def type_cast(value)
183
+ value
184
+ end
180
185
 
181
- def with_value_from_database(value)
182
- raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
186
+ def changed_in_place?
187
+ false
188
+ end
183
189
  end
184
- alias_method :with_value_from_user, :with_value_from_database
185
- end
186
190
 
187
- class Uninitialized < Attribute # :nodoc:
188
- UNINITIALIZED_ORIGINAL_VALUE = Object.new
191
+ class Null < Attribute # :nodoc:
192
+ def initialize(name)
193
+ super(name, nil, Type.default_value)
194
+ end
189
195
 
190
- def initialize(name, type)
191
- super(name, nil, type)
192
- end
196
+ def type_cast(*)
197
+ nil
198
+ end
193
199
 
194
- def value
195
- if block_given?
196
- yield name
200
+ def with_type(type)
201
+ self.class.with_cast_value(name, nil, type)
197
202
  end
198
- end
199
203
 
200
- def original_value
201
- UNINITIALIZED_ORIGINAL_VALUE
204
+ def with_value_from_database(value)
205
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
206
+ end
207
+ alias_method :with_value_from_user, :with_value_from_database
202
208
  end
203
209
 
204
- def value_for_database
205
- end
210
+ class Uninitialized < Attribute # :nodoc:
211
+ UNINITIALIZED_ORIGINAL_VALUE = Object.new
206
212
 
207
- def initialized?
208
- false
213
+ def initialize(name, type)
214
+ super(name, nil, type)
215
+ end
216
+
217
+ def value
218
+ if block_given?
219
+ yield name
220
+ end
221
+ end
222
+
223
+ def original_value
224
+ UNINITIALIZED_ORIGINAL_VALUE
225
+ end
226
+
227
+ def value_for_database
228
+ end
229
+
230
+ def initialized?
231
+ false
232
+ end
233
+
234
+ def with_type(type)
235
+ self.class.new(name, type)
236
+ end
209
237
  end
210
- end
211
- private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
238
+ private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
212
239
  end
213
240
  end