activerecord 4.2.11.3 → 5.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -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,5 +1,3 @@
1
- require 'active_support/core_ext/module/method_transplanting'
2
-
3
1
  module ActiveRecord
4
2
  module AttributeMethods
5
3
  module Read
@@ -36,68 +34,54 @@ module ActiveRecord
36
34
  extend ActiveSupport::Concern
37
35
 
38
36
  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
37
  protected
47
38
 
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}"
39
+ def define_method_attribute(name)
40
+ safe_name = name.unpack('h*'.freeze).first
41
+ temp_method = "__temp__#{safe_name}"
61
42
 
62
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
43
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
63
44
 
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
45
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
46
+ def #{temp_method}
47
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
48
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
74
49
  end
50
+ STR
51
+
52
+ generated_attribute_methods.module_eval do
53
+ alias_method name, temp_method
54
+ undef_method temp_method
75
55
  end
76
56
  end
77
57
  end
78
58
 
79
- ID = 'id'.freeze
80
-
81
59
  # Returns the value of the attribute identified by <tt>attr_name</tt> after
82
60
  # it has been typecast (for example, "2004-12-12" in a date column is cast
83
61
  # to a date object, like Date.new(2004, 12, 12)).
84
62
  def read_attribute(attr_name, &block)
85
63
  name = attr_name.to_s
86
- name = self.class.primary_key if name == ID
64
+ name = self.class.primary_key if name == 'id'.freeze
87
65
  _read_attribute(name, &block)
88
66
  end
89
67
 
90
68
  # This method exists to avoid the expensive primary_key check internally, without
91
69
  # 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? }
70
+ if defined?(JRUBY_VERSION)
71
+ # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
72
+ # https://github.com/jruby/jruby/pull/2562
73
+ def _read_attribute(attr_name, &block) # :nodoc
74
+ @attributes.fetch_value(attr_name.to_s, &block)
75
+ end
76
+ else
77
+ def _read_attribute(attr_name) # :nodoc:
78
+ @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
79
+ end
94
80
  end
95
81
 
96
- private
82
+ alias :attribute :_read_attribute
83
+ private :attribute
97
84
 
98
- def attribute(attribute_name)
99
- _read_attribute(attribute_name)
100
- end
101
85
  end
102
86
  end
103
87
  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,25 +1,29 @@
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)
11
+ def cast(value)
12
12
  if value.is_a?(Array)
13
- value.map { |v| type_cast_from_user(v) }
13
+ value.map { |v| cast(v) }
14
+ elsif 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
20
22
  end
21
23
  end
22
24
 
25
+ private
26
+
23
27
  def convert_time_to_time_zone(value)
24
28
  if value.is_a?(Array)
25
29
  value.map { |v| convert_time_to_time_zone(v) }
@@ -29,6 +33,10 @@ module ActiveRecord
29
33
  value
30
34
  end
31
35
  end
36
+
37
+ def set_time_zone_without_conversion(value)
38
+ ::Time.zone.local_to_utc(value).in_time_zone
39
+ end
32
40
  end
33
41
 
34
42
  extend ActiveSupport::Concern
@@ -39,6 +47,9 @@ module ActiveRecord
39
47
 
40
48
  class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
41
49
  self.skip_time_zone_conversion_for_attributes = []
50
+
51
+ class_attribute :time_zone_aware_types, instance_writer: false
52
+ self.time_zone_aware_types = [:datetime, :not_explicitly_configured]
42
53
  end
43
54
 
44
55
  module ClassMethods
@@ -59,9 +70,31 @@ module ActiveRecord
59
70
  end
60
71
 
61
72
  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)
73
+ enabled_for_column = time_zone_aware_attributes &&
74
+ !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
75
+ result = enabled_for_column &&
76
+ time_zone_aware_types.include?(cast_type.type)
77
+
78
+ if enabled_for_column &&
79
+ !result &&
80
+ cast_type.type == :time &&
81
+ time_zone_aware_types.include?(:not_explicitly_configured)
82
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
83
+ Time columns will become time zone aware in Rails 5.1. This
84
+ still causes `String`s to be parsed as if they were in `Time.zone`,
85
+ and `Time`s to be converted to `Time.zone`.
86
+
87
+ To keep the old behavior, you must add the following to your initializer:
88
+
89
+ config.active_record.time_zone_aware_types = [:datetime]
90
+
91
+ To silence this deprecation warning, add the following:
92
+
93
+ config.active_record.time_zone_aware_types << :time
94
+ MESSAGE
95
+ end
96
+
97
+ result
65
98
  end
66
99
  end
67
100
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext/module/method_transplanting'
2
-
3
1
  module ActiveRecord
4
2
  module AttributeMethods
5
3
  module Write
@@ -25,38 +23,29 @@ module ActiveRecord
25
23
  module ClassMethods
26
24
  protected
27
25
 
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
26
+ def define_method_attribute=(name)
27
+ safe_name = name.unpack('h*'.freeze).first
28
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
39
29
 
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
30
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
31
+ def __temp__#{safe_name}=(value)
32
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
33
+ write_attribute(name, value)
34
+ end
35
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
36
+ undef_method :__temp__#{safe_name}=
37
+ STR
49
38
  end
50
39
  end
51
40
 
52
41
  # Updates the attribute identified by <tt>attr_name</tt> with the
53
- # specified +value+. Empty strings for Integer and Float columns are
42
+ # specified +value+. Empty strings for fixnum and float columns are
54
43
  # turned into +nil+.
55
44
  def write_attribute(attr_name, value)
56
45
  write_attribute_with_type_cast(attr_name, value, true)
57
46
  end
58
47
 
59
- def raw_write_attribute(attr_name, value)
48
+ def raw_write_attribute(attr_name, value) # :nodoc:
60
49
  write_attribute_with_type_cast(attr_name, value, false)
61
50
  end
62
51
 
@@ -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
@@ -10,6 +10,10 @@ module ActiveRecord
10
10
  attributes[name] || Attribute.null(name)
11
11
  end
12
12
 
13
+ def []=(name, value)
14
+ attributes[name] = value
15
+ end
16
+
13
17
  def values_before_type_cast
14
18
  attributes.transform_values(&:value_before_type_cast)
15
19
  end
@@ -24,11 +28,19 @@ module ActiveRecord
24
28
  end
25
29
 
26
30
  def keys
27
- attributes.initialized_keys
31
+ attributes.each_key.select { |name| self[name].initialized? }
28
32
  end
29
33
 
30
- def fetch_value(name)
31
- self[name].value { |n| yield n if block_given? }
34
+ if defined?(JRUBY_VERSION)
35
+ # This form is significantly faster on JRuby, and this is one of our biggest hotspots.
36
+ # https://github.com/jruby/jruby/pull/2562
37
+ def fetch_value(name, &block)
38
+ self[name].value(&block)
39
+ end
40
+ else
41
+ def fetch_value(name)
42
+ self[name].value { |n| yield n if block_given? }
43
+ end
32
44
  end
33
45
 
34
46
  def write_from_database(name, value)
@@ -48,6 +60,12 @@ module ActiveRecord
48
60
  super
49
61
  end
50
62
 
63
+ def deep_dup
64
+ dup.tap do |copy|
65
+ copy.instance_variable_set(:@attributes, attributes.deep_dup)
66
+ end
67
+ end
68
+
51
69
  def initialize_dup(_)
52
70
  @attributes = attributes.dup
53
71
  super
@@ -64,6 +82,15 @@ module ActiveRecord
64
82
  end
65
83
  end
66
84
 
85
+ def accessed
86
+ attributes.select { |_, attr| attr.has_been_read? }.keys
87
+ end
88
+
89
+ def map(&block)
90
+ new_attributes = attributes.transform_values(&block)
91
+ AttributeSet.new(new_attributes)
92
+ end
93
+
67
94
  def ==(other)
68
95
  attributes == other.attributes
69
96
  end
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  end
23
23
 
24
24
  class LazyAttributeHash # :nodoc:
25
- delegate :transform_values, to: :materialize
25
+ delegate :transform_values, :each_key, to: :materialize
26
26
 
27
27
  def initialize(types, values, additional_types)
28
28
  @types = types
@@ -47,12 +47,14 @@ module ActiveRecord
47
47
  delegate_hash[key] = value
48
48
  end
49
49
 
50
- def initialized_keys
51
- delegate_hash.keys | values.keys
50
+ def deep_dup
51
+ dup.tap do |copy|
52
+ copy.instance_variable_set(:@delegate_hash, delegate_hash.transform_values(&:dup))
53
+ end
52
54
  end
53
55
 
54
56
  def initialize_dup(_)
55
- @delegate_hash = delegate_hash.transform_values(&:dup)
57
+ @delegate_hash = Hash[delegate_hash]
56
58
  super
57
59
  end
58
60