activerecord 4.2.11.1 → 5.0.0

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 (246) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1282 -1195
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record.rb +8 -4
  8. data/lib/active_record/aggregations.rb +35 -24
  9. data/lib/active_record/association_relation.rb +3 -3
  10. data/lib/active_record/associations.rb +317 -209
  11. data/lib/active_record/associations/alias_tracker.rb +19 -16
  12. data/lib/active_record/associations/association.rb +11 -9
  13. data/lib/active_record/associations/association_scope.rb +73 -102
  14. data/lib/active_record/associations/belongs_to_association.rb +21 -32
  15. data/lib/active_record/associations/builder/association.rb +28 -34
  16. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  17. data/lib/active_record/associations/builder/collection_association.rb +7 -19
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
  19. data/lib/active_record/associations/builder/has_many.rb +4 -4
  20. data/lib/active_record/associations/builder/has_one.rb +11 -6
  21. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  22. data/lib/active_record/associations/collection_association.rb +49 -41
  23. data/lib/active_record/associations/collection_proxy.rb +67 -27
  24. data/lib/active_record/associations/foreign_association.rb +1 -1
  25. data/lib/active_record/associations/has_many_association.rb +20 -71
  26. data/lib/active_record/associations/has_many_through_association.rb +8 -47
  27. data/lib/active_record/associations/has_one_association.rb +12 -5
  28. data/lib/active_record/associations/join_dependency.rb +29 -19
  29. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  30. data/lib/active_record/associations/preloader.rb +14 -4
  31. data/lib/active_record/associations/preloader/association.rb +46 -52
  32. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  33. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  35. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  36. data/lib/active_record/associations/singular_association.rb +7 -1
  37. data/lib/active_record/associations/through_association.rb +11 -3
  38. data/lib/active_record/attribute.rb +68 -18
  39. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  40. data/lib/active_record/attribute_assignment.rb +19 -140
  41. data/lib/active_record/attribute_decorators.rb +6 -5
  42. data/lib/active_record/attribute_methods.rb +76 -47
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  44. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  45. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  46. data/lib/active_record/attribute_methods/query.rb +2 -2
  47. data/lib/active_record/attribute_methods/read.rb +31 -59
  48. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
  50. data/lib/active_record/attribute_methods/write.rb +13 -37
  51. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  52. data/lib/active_record/attribute_set.rb +30 -3
  53. data/lib/active_record/attribute_set/builder.rb +6 -4
  54. data/lib/active_record/attributes.rb +199 -81
  55. data/lib/active_record/autosave_association.rb +49 -16
  56. data/lib/active_record/base.rb +32 -23
  57. data/lib/active_record/callbacks.rb +39 -43
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +20 -8
  60. data/lib/active_record/collection_cache_key.rb +40 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
  62. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  63. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
  64. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
  65. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
  66. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  67. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
  69. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  70. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
  71. data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
  72. data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
  73. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
  74. data/lib/active_record/connection_adapters/column.rb +28 -43
  75. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  76. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  77. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  78. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  79. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  80. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  83. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  84. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  85. data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
  88. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
  91. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +37 -14
  121. data/lib/active_record/core.rb +89 -107
  122. data/lib/active_record/counter_cache.rb +13 -24
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +113 -76
  125. data/lib/active_record/errors.rb +87 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +76 -40
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +15 -15
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration.rb +363 -133
  140. data/lib/active_record/migration/command_recorder.rb +59 -18
  141. data/lib/active_record/migration/compatibility.rb +126 -0
  142. data/lib/active_record/model_schema.rb +129 -41
  143. data/lib/active_record/nested_attributes.rb +58 -29
  144. data/lib/active_record/null_relation.rb +16 -8
  145. data/lib/active_record/persistence.rb +121 -80
  146. data/lib/active_record/query_cache.rb +15 -18
  147. data/lib/active_record/querying.rb +10 -9
  148. data/lib/active_record/railtie.rb +23 -16
  149. data/lib/active_record/railties/controller_runtime.rb +1 -1
  150. data/lib/active_record/railties/databases.rake +69 -46
  151. data/lib/active_record/readonly_attributes.rb +1 -1
  152. data/lib/active_record/reflection.rb +282 -115
  153. data/lib/active_record/relation.rb +176 -116
  154. data/lib/active_record/relation/batches.rb +139 -34
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  156. data/lib/active_record/relation/calculations.rb +79 -108
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +163 -81
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +16 -42
  161. data/lib/active_record/relation/predicate_builder.rb +120 -107
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  163. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  164. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  166. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  167. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  168. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  169. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +308 -244
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +4 -7
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/result.rb +4 -3
  177. data/lib/active_record/runtime_registry.rb +1 -1
  178. data/lib/active_record/sanitization.rb +95 -66
  179. data/lib/active_record/schema.rb +26 -22
  180. data/lib/active_record/schema_dumper.rb +62 -38
  181. data/lib/active_record/schema_migration.rb +11 -14
  182. data/lib/active_record/scoping.rb +32 -15
  183. data/lib/active_record/scoping/default.rb +23 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/secure_token.rb +38 -0
  186. data/lib/active_record/serialization.rb +2 -4
  187. data/lib/active_record/statement_cache.rb +16 -14
  188. data/lib/active_record/store.rb +8 -3
  189. data/lib/active_record/suppressor.rb +58 -0
  190. data/lib/active_record/table_metadata.rb +68 -0
  191. data/lib/active_record/tasks/database_tasks.rb +57 -43
  192. data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
  193. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  194. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  195. data/lib/active_record/timestamp.rb +20 -9
  196. data/lib/active_record/touch_later.rb +58 -0
  197. data/lib/active_record/transactions.rb +138 -56
  198. data/lib/active_record/type.rb +66 -17
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -45
  201. data/lib/active_record/type/date_time.rb +2 -49
  202. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  203. data/lib/active_record/type/internal/timezone.rb +15 -0
  204. data/lib/active_record/type/serialized.rb +15 -14
  205. data/lib/active_record/type/time.rb +10 -16
  206. data/lib/active_record/type/type_map.rb +4 -4
  207. data/lib/active_record/type_caster.rb +7 -0
  208. data/lib/active_record/type_caster/connection.rb +29 -0
  209. data/lib/active_record/type_caster/map.rb +19 -0
  210. data/lib/active_record/validations.rb +33 -32
  211. data/lib/active_record/validations/absence.rb +23 -0
  212. data/lib/active_record/validations/associated.rb +10 -3
  213. data/lib/active_record/validations/length.rb +24 -0
  214. data/lib/active_record/validations/presence.rb +11 -12
  215. data/lib/active_record/validations/uniqueness.rb +30 -29
  216. data/lib/rails/generators/active_record/migration.rb +7 -0
  217. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  218. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  219. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
  220. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  221. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  222. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  223. metadata +59 -34
  224. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  225. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  226. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  227. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  228. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  229. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  231. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  232. data/lib/active_record/type/big_integer.rb +0 -13
  233. data/lib/active_record/type/binary.rb +0 -50
  234. data/lib/active_record/type/boolean.rb +0 -31
  235. data/lib/active_record/type/decimal.rb +0 -64
  236. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  237. data/lib/active_record/type/decorator.rb +0 -14
  238. data/lib/active_record/type/float.rb +0 -19
  239. data/lib/active_record/type/integer.rb +0 -59
  240. data/lib/active_record/type/mutable.rb +0 -16
  241. data/lib/active_record/type/numeric.rb +0 -36
  242. data/lib/active_record/type/string.rb +0 -40
  243. data/lib/active_record/type/text.rb +0 -11
  244. data/lib/active_record/type/time_value.rb +0 -38
  245. data/lib/active_record/type/unsigned_integer.rb +0 -15
  246. data/lib/active_record/type/value.rb +0 -110
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  module PrimaryKey
6
6
  extend ActiveSupport::Concern
7
7
 
8
- # Returns this record's primary key value wrapped in an Array if one is
8
+ # Returns this record's primary key value wrapped in an array if one is
9
9
  # available.
10
10
  def to_key
11
11
  sync_with_transaction_state
@@ -108,7 +108,7 @@ module ActiveRecord
108
108
  # self.primary_key = 'sysid'
109
109
  # end
110
110
  #
111
- # You can also define the +primary_key+ method yourself:
111
+ # You can also define the #primary_key method yourself:
112
112
  #
113
113
  # class Project < ActiveRecord::Base
114
114
  # def self.primary_key
@@ -19,10 +19,10 @@ module ActiveRecord
19
19
  if Numeric === value || value !~ /[^0-9]/
20
20
  !value.to_i.zero?
21
21
  else
22
- return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
22
+ return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
23
23
  !value.blank?
24
24
  end
25
- elsif column.number?
25
+ elsif value.respond_to?(:zero?)
26
26
  !value.zero?
27
27
  else
28
28
  !value.blank?
@@ -1,10 +1,11 @@
1
- require 'active_support/core_ext/module/method_transplanting'
2
-
3
1
  module ActiveRecord
4
2
  module AttributeMethods
5
3
  module Read
6
- ReaderMethodCache = Class.new(AttributeMethodCache) {
7
- private
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ protected
8
+
8
9
  # We want to generate the methods via module_eval rather than
9
10
  # define_method, because define_method is slower on dispatch.
10
11
  # Evaluating many similar methods may use more memory as the instruction
@@ -23,81 +24,52 @@ module ActiveRecord
23
24
  # to allocate an object on each call to the attribute method.
24
25
  # Making it frozen means that it doesn't get duped when used to
25
26
  # key the @attributes in read_attribute.
26
- def method_body(method_name, const_name)
27
- <<-EOMETHOD
28
- def #{method_name}
29
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name}
30
- _read_attribute(name) { |n| missing_attribute(n, caller) }
31
- end
32
- EOMETHOD
33
- end
34
- }.new
35
-
36
- extend ActiveSupport::Concern
37
-
38
- module ClassMethods
39
- [:cache_attributes, :cached_attributes, :cache_attribute?].each do |method_name|
40
- define_method method_name do |*|
41
- cached_attributes_deprecation_warning(method_name)
42
- true
43
- end
44
- end
45
-
46
- protected
47
-
48
- def cached_attributes_deprecation_warning(method_name)
49
- ActiveSupport::Deprecation.warn "Calling `#{method_name}` is no longer necessary. All attributes are cached."
50
- end
51
-
52
- if Module.methods_transplantable?
53
- def define_method_attribute(name)
54
- method = ReaderMethodCache[name]
55
- generated_attribute_methods.module_eval { define_method name, method }
56
- end
57
- else
58
- def define_method_attribute(name)
59
- safe_name = name.unpack('h*').first
60
- temp_method = "__temp__#{safe_name}"
27
+ def define_method_attribute(name)
28
+ safe_name = name.unpack('h*'.freeze).first
29
+ temp_method = "__temp__#{safe_name}"
61
30
 
62
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
31
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
63
32
 
64
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
65
- def #{temp_method}
66
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
67
- _read_attribute(name) { |n| missing_attribute(n, caller) }
68
- end
69
- STR
70
-
71
- generated_attribute_methods.module_eval do
72
- alias_method name, temp_method
73
- undef_method temp_method
33
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
34
+ def #{temp_method}
35
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
36
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
74
37
  end
38
+ STR
39
+
40
+ generated_attribute_methods.module_eval do
41
+ alias_method name, temp_method
42
+ undef_method temp_method
75
43
  end
76
44
  end
77
45
  end
78
46
 
79
- ID = 'id'.freeze
80
-
81
47
  # Returns the value of the attribute identified by <tt>attr_name</tt> after
82
48
  # it has been typecast (for example, "2004-12-12" in a date column is cast
83
49
  # to a date object, like Date.new(2004, 12, 12)).
84
50
  def read_attribute(attr_name, &block)
85
51
  name = attr_name.to_s
86
- name = self.class.primary_key if name == ID
52
+ name = self.class.primary_key if name == 'id'.freeze
87
53
  _read_attribute(name, &block)
88
54
  end
89
55
 
90
56
  # This method exists to avoid the expensive primary_key check internally, without
91
57
  # breaking compatibility with the read_attribute API
92
- def _read_attribute(attr_name) # :nodoc:
93
- @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
58
+ if defined?(JRUBY_VERSION)
59
+ # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
60
+ # https://github.com/jruby/jruby/pull/2562
61
+ def _read_attribute(attr_name, &block) # :nodoc
62
+ @attributes.fetch_value(attr_name.to_s, &block)
63
+ end
64
+ else
65
+ def _read_attribute(attr_name) # :nodoc:
66
+ @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
67
+ end
94
68
  end
95
69
 
96
- private
70
+ alias :attribute :_read_attribute
71
+ private :attribute
97
72
 
98
- def attribute(attribute_name)
99
- _read_attribute(attribute_name)
100
- end
101
73
  end
102
74
  end
103
75
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/string/filters'
2
-
3
1
  module ActiveRecord
4
2
  module AttributeMethods
5
3
  module Serialization
@@ -11,7 +9,19 @@ module ActiveRecord
11
9
  # attribute using this method and it will be handled automatically. The
12
10
  # serialization is done through YAML. If +class_name+ is specified, the
13
11
  # serialized object must be of that class on assignment and retrieval.
14
- # Otherwise <tt>SerializationTypeMismatch</tt> will be raised.
12
+ # Otherwise SerializationTypeMismatch will be raised.
13
+ #
14
+ # Empty objects as <tt>{}</tt>, in the case of +Hash+, or <tt>[]</tt>, in the case of
15
+ # +Array+, will always be persisted as null.
16
+ #
17
+ # Keep in mind that database adapters handle certain serialization tasks
18
+ # for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
19
+ # converted between JSON object/array syntax and Ruby +Hash+ or +Array+
20
+ # objects transparently. There is no need to use #serialize in this
21
+ # case.
22
+ #
23
+ # For more complex cases, such as conversion to or from your application
24
+ # domain objects, consider using the ActiveRecord::Attributes API.
15
25
  #
16
26
  # ==== Parameters
17
27
  #
@@ -51,19 +61,6 @@ module ActiveRecord
51
61
  Type::Serialized.new(type, coder)
52
62
  end
53
63
  end
54
-
55
- def serialized_attributes
56
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
57
- `serialized_attributes` is deprecated without replacement, and will
58
- be removed in Rails 5.0.
59
- MSG
60
-
61
- @serialized_attributes ||= Hash[
62
- columns.select { |t| t.cast_type.is_a?(Type::Serialized) }.map { |c|
63
- [c.name, c.cast_type.coder]
64
- }
65
- ]
66
- end
67
64
  end
68
65
  end
69
66
  end
@@ -1,32 +1,54 @@
1
+ require 'active_support/core_ext/string/strip'
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  module TimeZoneConversion
4
6
  class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
5
- include Type::Decorator
6
-
7
- def type_cast_from_database(value)
7
+ def deserialize(value)
8
8
  convert_time_to_time_zone(super)
9
9
  end
10
10
 
11
- def type_cast_from_user(value)
12
- if value.is_a?(Array)
13
- value.map { |v| type_cast_from_user(v) }
11
+ def cast(value)
12
+ return if value.nil?
13
+
14
+ if value.is_a?(Hash)
15
+ set_time_zone_without_conversion(super)
14
16
  elsif value.respond_to?(:in_time_zone)
15
17
  begin
16
- value.in_time_zone || super
18
+ super(user_input_in_time_zone(value)) || super
17
19
  rescue ArgumentError
18
20
  nil
19
21
  end
22
+ else
23
+ map_avoiding_infinite_recursion(super) { |v| cast(v) }
20
24
  end
21
25
  end
22
26
 
27
+ private
28
+
23
29
  def convert_time_to_time_zone(value)
24
- if value.is_a?(Array)
25
- value.map { |v| convert_time_to_time_zone(v) }
26
- elsif value.acts_like?(:time)
30
+ return if value.nil?
31
+
32
+ if value.acts_like?(:time)
27
33
  value.in_time_zone
28
- else
34
+ elsif value.is_a?(::Float)
29
35
  value
36
+ else
37
+ map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
38
+ end
39
+ end
40
+
41
+ def set_time_zone_without_conversion(value)
42
+ ::Time.zone.local_to_utc(value).in_time_zone
43
+ end
44
+
45
+ def map_avoiding_infinite_recursion(value)
46
+ map(value) do |v|
47
+ if value.equal?(v)
48
+ nil
49
+ else
50
+ yield(v)
51
+ end
30
52
  end
31
53
  end
32
54
  end
@@ -39,6 +61,9 @@ module ActiveRecord
39
61
 
40
62
  class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
41
63
  self.skip_time_zone_conversion_for_attributes = []
64
+
65
+ class_attribute :time_zone_aware_types, instance_writer: false
66
+ self.time_zone_aware_types = [:datetime, :not_explicitly_configured]
42
67
  end
43
68
 
44
69
  module ClassMethods
@@ -59,9 +84,31 @@ module ActiveRecord
59
84
  end
60
85
 
61
86
  def create_time_zone_conversion_attribute?(name, cast_type)
62
- time_zone_aware_attributes &&
63
- !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
64
- (:datetime == cast_type.type)
87
+ enabled_for_column = time_zone_aware_attributes &&
88
+ !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
89
+ result = enabled_for_column &&
90
+ time_zone_aware_types.include?(cast_type.type)
91
+
92
+ if enabled_for_column &&
93
+ !result &&
94
+ cast_type.type == :time &&
95
+ time_zone_aware_types.include?(:not_explicitly_configured)
96
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
97
+ Time columns will become time zone aware in Rails 5.1. This
98
+ still causes `String`s to be parsed as if they were in `Time.zone`,
99
+ and `Time`s to be converted to `Time.zone`.
100
+
101
+ To keep the old behavior, you must add the following to your initializer:
102
+
103
+ config.active_record.time_zone_aware_types = [:datetime]
104
+
105
+ To silence this deprecation warning, add the following:
106
+
107
+ config.active_record.time_zone_aware_types = [:datetime, :time]
108
+ MESSAGE
109
+ end
110
+
111
+ result
65
112
  end
66
113
  end
67
114
  end
@@ -1,21 +1,6 @@
1
- require 'active_support/core_ext/module/method_transplanting'
2
-
3
1
  module ActiveRecord
4
2
  module AttributeMethods
5
3
  module Write
6
- WriterMethodCache = Class.new(AttributeMethodCache) {
7
- private
8
-
9
- def method_body(method_name, const_name)
10
- <<-EOMETHOD
11
- def #{method_name}(value)
12
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name}
13
- write_attribute(name, value)
14
- end
15
- EOMETHOD
16
- end
17
- }.new
18
-
19
4
  extend ActiveSupport::Concern
20
5
 
21
6
  included do
@@ -25,27 +10,18 @@ module ActiveRecord
25
10
  module ClassMethods
26
11
  protected
27
12
 
28
- if Module.methods_transplantable?
29
- def define_method_attribute=(name)
30
- method = WriterMethodCache[name]
31
- generated_attribute_methods.module_eval {
32
- define_method "#{name}=", method
33
- }
34
- end
35
- else
36
- def define_method_attribute=(name)
37
- safe_name = name.unpack('h*').first
38
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
39
-
40
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
41
- def __temp__#{safe_name}=(value)
42
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
43
- write_attribute(name, value)
44
- end
45
- alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
46
- undef_method :__temp__#{safe_name}=
47
- STR
48
- end
13
+ def define_method_attribute=(name)
14
+ safe_name = name.unpack('h*'.freeze).first
15
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
16
+
17
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
18
+ def __temp__#{safe_name}=(value)
19
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
20
+ write_attribute(name, value)
21
+ end
22
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
23
+ undef_method :__temp__#{safe_name}=
24
+ STR
49
25
  end
50
26
  end
51
27
 
@@ -56,7 +32,7 @@ module ActiveRecord
56
32
  write_attribute_with_type_cast(attr_name, value, true)
57
33
  end
58
34
 
59
- def raw_write_attribute(attr_name, value)
35
+ def raw_write_attribute(attr_name, value) # :nodoc:
60
36
  write_attribute_with_type_cast(attr_name, value, false)
61
37
  end
62
38
 
@@ -0,0 +1,70 @@
1
+ module ActiveRecord
2
+ class AttributeMutationTracker # :nodoc:
3
+ def initialize(attributes)
4
+ @attributes = attributes
5
+ end
6
+
7
+ def changed_values
8
+ attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
9
+ if changed?(attr_name)
10
+ result[attr_name] = attributes[attr_name].original_value
11
+ end
12
+ end
13
+ end
14
+
15
+ def changes
16
+ attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
17
+ if changed?(attr_name)
18
+ result[attr_name] = [attributes[attr_name].original_value, attributes.fetch_value(attr_name)]
19
+ end
20
+ end
21
+ end
22
+
23
+ def changed?(attr_name)
24
+ attr_name = attr_name.to_s
25
+ attributes[attr_name].changed?
26
+ end
27
+
28
+ def changed_in_place?(attr_name)
29
+ attributes[attr_name].changed_in_place?
30
+ end
31
+
32
+ def forget_change(attr_name)
33
+ attr_name = attr_name.to_s
34
+ attributes[attr_name] = attributes[attr_name].forgetting_assignment
35
+ end
36
+
37
+ protected
38
+
39
+ attr_reader :attributes
40
+
41
+ private
42
+
43
+ def attr_names
44
+ attributes.keys
45
+ end
46
+ end
47
+
48
+ class NullMutationTracker # :nodoc:
49
+ include Singleton
50
+
51
+ def changed_values
52
+ {}
53
+ end
54
+
55
+ def changes
56
+ {}
57
+ end
58
+
59
+ def changed?(*)
60
+ false
61
+ end
62
+
63
+ def changed_in_place?(*)
64
+ false
65
+ end
66
+
67
+ def forget_change(*)
68
+ end
69
+ end
70
+ end