activerecord 3.1.10 → 4.2.11

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 (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -0,0 +1,70 @@
1
+ require 'active_support/core_ext/string/filters'
2
+
3
+ module ActiveRecord
4
+ module AttributeMethods
5
+ module Serialization
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # If you have an attribute that needs to be saved to the database as an
10
+ # object, and retrieved as the same object, then specify the name of that
11
+ # attribute using this method and it will be handled automatically. The
12
+ # serialization is done through YAML. If +class_name+ is specified, the
13
+ # serialized object must be of that class on assignment and retrieval.
14
+ # Otherwise <tt>SerializationTypeMismatch</tt> will be raised.
15
+ #
16
+ # ==== Parameters
17
+ #
18
+ # * +attr_name+ - The field name that should be serialized.
19
+ # * +class_name_or_coder+ - Optional, a coder object, which responds to `.load` / `.dump`
20
+ # or a class name that the object type should be equal to.
21
+ #
22
+ # ==== Example
23
+ #
24
+ # # Serialize a preferences attribute.
25
+ # class User < ActiveRecord::Base
26
+ # serialize :preferences
27
+ # end
28
+ #
29
+ # # Serialize preferences using JSON as coder.
30
+ # class User < ActiveRecord::Base
31
+ # serialize :preferences, JSON
32
+ # end
33
+ #
34
+ # # Serialize preferences as Hash using YAML coder.
35
+ # class User < ActiveRecord::Base
36
+ # serialize :preferences, Hash
37
+ # end
38
+ def serialize(attr_name, class_name_or_coder = Object)
39
+ # When ::JSON is used, force it to go through the Active Support JSON encoder
40
+ # to ensure special objects (e.g. Active Record models) are dumped correctly
41
+ # using the #as_json hook.
42
+ coder = if class_name_or_coder == ::JSON
43
+ Coders::JSON
44
+ elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
45
+ class_name_or_coder
46
+ else
47
+ Coders::YAMLColumn.new(class_name_or_coder)
48
+ end
49
+
50
+ decorate_attribute_type(attr_name, :serialize) do |type|
51
+ Type::Serialized.new(type, coder)
52
+ end
53
+ 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
+ end
68
+ end
69
+ end
70
+ end
@@ -1,66 +1,68 @@
1
- require 'active_support/core_ext/class/attribute'
2
- require 'active_support/core_ext/object/inclusion'
3
-
4
1
  module ActiveRecord
5
2
  module AttributeMethods
6
3
  module TimeZoneConversion
4
+ class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
5
+ include Type::Decorator
6
+
7
+ def type_cast_from_database(value)
8
+ convert_time_to_time_zone(super)
9
+ end
10
+
11
+ def type_cast_from_user(value)
12
+ if value.is_a?(Array)
13
+ value.map { |v| type_cast_from_user(v) }
14
+ elsif value.respond_to?(:in_time_zone)
15
+ begin
16
+ value.in_time_zone || super
17
+ rescue ArgumentError
18
+ nil
19
+ end
20
+ end
21
+ end
22
+
23
+ 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)
27
+ value.in_time_zone
28
+ else
29
+ value
30
+ end
31
+ end
32
+ end
33
+
7
34
  extend ActiveSupport::Concern
8
35
 
9
36
  included do
10
- cattr_accessor :time_zone_aware_attributes, :instance_writer => false
37
+ mattr_accessor :time_zone_aware_attributes, instance_writer: false
11
38
  self.time_zone_aware_attributes = false
12
39
 
13
- class_attribute :skip_time_zone_conversion_for_attributes, :instance_writer => false
40
+ class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
14
41
  self.skip_time_zone_conversion_for_attributes = []
15
42
  end
16
43
 
17
44
  module ClassMethods
18
- protected
19
- # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
20
- # This enhanced read method automatically converts the UTC time stored in the database to the time
21
- # zone stored in Time.zone.
22
- def define_method_attribute(attr_name)
23
- if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
24
- method_body, line = <<-EOV, __LINE__ + 1
25
- def _#{attr_name}
26
- cached = @attributes_cache['#{attr_name}']
27
- return cached if cached
28
- time = _read_attribute('#{attr_name}')
29
- @attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
30
- end
31
- alias #{attr_name} _#{attr_name}
32
- EOV
33
- generated_attribute_methods.module_eval(method_body, __FILE__, line)
34
- else
35
- super
36
- end
37
- end
45
+ private
38
46
 
39
- # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
40
- # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
41
- def define_method_attribute=(attr_name)
42
- if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
43
- method_body, line = <<-EOV, __LINE__ + 1
44
- def #{attr_name}=(original_time)
45
- time = original_time
46
- unless time.acts_like?(:time)
47
- time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time
48
- end
49
- time = time.in_time_zone rescue nil if time
50
- write_attribute(:#{attr_name}, original_time)
51
- @attributes_cache["#{attr_name}"] = time
52
- end
53
- EOV
54
- generated_attribute_methods.module_eval(method_body, __FILE__, line)
55
- else
56
- super
47
+ def inherited(subclass)
48
+ # We need to apply this decorator here, rather than on module inclusion. The closure
49
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
50
+ # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
51
+ # `skip_time_zone_conversion_for_attributes` would not be picked up.
52
+ subclass.class_eval do
53
+ matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
54
+ decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
55
+ TimeZoneConverter.new(type)
57
56
  end
58
57
  end
58
+ super
59
+ end
59
60
 
60
- private
61
- def create_time_zone_conversion_attribute?(name, column)
62
- time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) && column.type.in?([:datetime, :timestamp])
63
- end
61
+ 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)
65
+ end
64
66
  end
65
67
  end
66
68
  end
@@ -1,6 +1,21 @@
1
+ require 'active_support/core_ext/module/method_transplanting'
2
+
1
3
  module ActiveRecord
2
4
  module AttributeMethods
3
5
  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
+
4
19
  extend ActiveSupport::Concern
5
20
 
6
21
  included do
@@ -9,36 +24,60 @@ module ActiveRecord
9
24
 
10
25
  module ClassMethods
11
26
  protected
12
- def define_method_attribute=(attr_name)
13
- if attr_name =~ ActiveModel::AttributeMethods::COMPILABLE_REGEXP
14
- generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__)
15
- else
16
- generated_attribute_methods.send(:define_method, "#{attr_name}=") do |new_value|
17
- write_attribute(attr_name, new_value)
27
+
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)
18
44
  end
19
- end
45
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
46
+ undef_method :__temp__#{safe_name}=
47
+ STR
20
48
  end
49
+ end
21
50
  end
22
51
 
23
- # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings
24
- # for fixnum and float columns are turned into +nil+.
52
+ # Updates the attribute identified by <tt>attr_name</tt> with the
53
+ # specified +value+. Empty strings for Integer and Float columns are
54
+ # turned into +nil+.
25
55
  def write_attribute(attr_name, value)
26
- attr_name = attr_name.to_s
27
- attr_name = self.class.primary_key if attr_name == 'id'
28
- @attributes_cache.delete(attr_name)
29
- if (column = column_for_attribute(attr_name)) && column.number?
30
- @attributes[attr_name] = convert_number_column_value(value)
31
- else
32
- @attributes[attr_name] = value
33
- end
56
+ write_attribute_with_type_cast(attr_name, value, true)
57
+ end
58
+
59
+ def raw_write_attribute(attr_name, value)
60
+ write_attribute_with_type_cast(attr_name, value, false)
34
61
  end
35
- alias_method :raw_write_attribute, :write_attribute
36
62
 
37
63
  private
38
- # Handle *= for method_missing.
39
- def attribute=(attribute_name, value)
40
- write_attribute(attribute_name, value)
64
+ # Handle *= for method_missing.
65
+ def attribute=(attribute_name, value)
66
+ write_attribute(attribute_name, value)
67
+ end
68
+
69
+ def write_attribute_with_type_cast(attr_name, value, should_type_cast)
70
+ attr_name = attr_name.to_s
71
+ attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
72
+
73
+ if should_type_cast
74
+ @attributes.write_from_user(attr_name, value)
75
+ else
76
+ @attributes.write_cast_value(attr_name, value)
41
77
  end
78
+
79
+ value
80
+ end
42
81
  end
43
82
  end
44
83
  end