activerecord 4.1.15 → 4.2.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1162 -1792
- data/README.rdoc +15 -10
- data/lib/active_record.rb +4 -0
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +56 -94
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration.rb +71 -46
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -15,9 +15,10 @@ module ActiveRecord
|
|
15
15
|
|
16
16
|
# Returns the primary key value.
|
17
17
|
def id
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
if pk = self.class.primary_key
|
19
|
+
sync_with_transaction_state
|
20
|
+
_read_attribute(pk)
|
21
|
+
end
|
21
22
|
end
|
22
23
|
|
23
24
|
# Sets the primary key value.
|
@@ -88,12 +89,9 @@ module ActiveRecord
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def get_primary_key(base_name) #:nodoc:
|
91
|
-
|
92
|
-
|
93
|
-
case primary_key_prefix_type
|
94
|
-
when :table_name
|
92
|
+
if base_name && primary_key_prefix_type == :table_name
|
95
93
|
base_name.foreign_key(false)
|
96
|
-
|
94
|
+
elsif base_name && primary_key_prefix_type == :table_name_with_underscore
|
97
95
|
base_name.foreign_key
|
98
96
|
else
|
99
97
|
if ActiveRecord::Base != self && table_exists?
|
@@ -122,6 +120,7 @@ module ActiveRecord
|
|
122
120
|
def primary_key=(value)
|
123
121
|
@primary_key = value && value.to_s
|
124
122
|
@quoted_primary_key = nil
|
123
|
+
@attributes_builder = nil
|
125
124
|
end
|
126
125
|
end
|
127
126
|
end
|
@@ -22,12 +22,12 @@ module ActiveRecord
|
|
22
22
|
# the attribute name. Using a constant means that we do not have
|
23
23
|
# to allocate an object on each call to the attribute method.
|
24
24
|
# Making it frozen means that it doesn't get duped when used to
|
25
|
-
# key the @
|
25
|
+
# key the @attributes in read_attribute.
|
26
26
|
def method_body(method_name, const_name)
|
27
27
|
<<-EOMETHOD
|
28
28
|
def #{method_name}
|
29
29
|
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name}
|
30
|
-
|
30
|
+
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
31
31
|
end
|
32
32
|
EOMETHOD
|
33
33
|
end
|
@@ -35,35 +35,20 @@ module ActiveRecord
|
|
35
35
|
|
36
36
|
extend ActiveSupport::Concern
|
37
37
|
|
38
|
-
ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date]
|
39
|
-
|
40
|
-
included do
|
41
|
-
class_attribute :attribute_types_cached_by_default, instance_writer: false
|
42
|
-
self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
43
|
-
end
|
44
|
-
|
45
38
|
module ClassMethods
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
cached_attributes.merge attribute_names.map { |attr| attr.to_s }
|
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
|
52
44
|
end
|
53
45
|
|
54
|
-
|
55
|
-
# with datatype <tt>:datetime, :timestamp, :time, :date</tt> are cached.
|
56
|
-
def cached_attributes
|
57
|
-
@cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set
|
58
|
-
end
|
46
|
+
protected
|
59
47
|
|
60
|
-
|
61
|
-
|
62
|
-
cached_attributes.include?(attr_name)
|
48
|
+
def cached_attributes_deprecation_warning(method_name)
|
49
|
+
ActiveSupport::Deprecation.warn "Calling `#{method_name}` is no longer necessary. All attributes are cached."
|
63
50
|
end
|
64
51
|
|
65
|
-
protected
|
66
|
-
|
67
52
|
if Module.methods_transplantable?
|
68
53
|
def define_method_attribute(name)
|
69
54
|
method = ReaderMethodCache[name]
|
@@ -79,7 +64,7 @@ module ActiveRecord
|
|
79
64
|
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
80
65
|
def #{temp_method}
|
81
66
|
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
82
|
-
|
67
|
+
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
83
68
|
end
|
84
69
|
STR
|
85
70
|
|
@@ -89,51 +74,29 @@ module ActiveRecord
|
|
89
74
|
end
|
90
75
|
end
|
91
76
|
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def cacheable_column?(column)
|
96
|
-
if attribute_types_cached_by_default == ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
97
|
-
! serialized_attributes.include? column.name
|
98
|
-
else
|
99
|
-
attribute_types_cached_by_default.include?(column.type)
|
100
|
-
end
|
101
|
-
end
|
102
77
|
end
|
103
78
|
|
79
|
+
ID = 'id'.freeze
|
80
|
+
|
104
81
|
# Returns the value of the attribute identified by <tt>attr_name</tt> after
|
105
82
|
# it has been typecast (for example, "2004-12-12" in a date column is cast
|
106
83
|
# to a date object, like Date.new(2004, 12, 12)).
|
107
|
-
def read_attribute(attr_name)
|
108
|
-
# If it's cached, just return it
|
109
|
-
# We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
|
84
|
+
def read_attribute(attr_name, &block)
|
110
85
|
name = attr_name.to_s
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
return @attributes.fetch(name) {
|
116
|
-
if name == 'id' && self.class.primary_key != name
|
117
|
-
read_attribute(self.class.primary_key)
|
118
|
-
end
|
119
|
-
} unless column
|
120
|
-
|
121
|
-
value = @attributes.fetch(name) {
|
122
|
-
return block_given? ? yield(name) : nil
|
123
|
-
}
|
86
|
+
name = self.class.primary_key if name == ID
|
87
|
+
_read_attribute(name, &block)
|
88
|
+
end
|
124
89
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
end
|
130
|
-
}
|
90
|
+
# This method exists to avoid the expensive primary_key check internally, without
|
91
|
+
# 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? }
|
131
94
|
end
|
132
95
|
|
133
96
|
private
|
134
97
|
|
135
98
|
def attribute(attribute_name)
|
136
|
-
|
99
|
+
_read_attribute(attribute_name)
|
137
100
|
end
|
138
101
|
end
|
139
102
|
end
|
@@ -1,31 +1,17 @@
|
|
1
|
+
require 'active_support/core_ext/string/filters'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module Serialization
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
|
6
|
-
included do
|
7
|
-
# Returns a hash of all the attributes that have been specified for
|
8
|
-
# serialization as keys and their class restriction as values.
|
9
|
-
class_attribute :serialized_attributes, instance_accessor: false
|
10
|
-
self.serialized_attributes = {}
|
11
|
-
end
|
12
|
-
|
13
8
|
module ClassMethods
|
14
|
-
##
|
15
|
-
# :method: serialized_attributes
|
16
|
-
#
|
17
|
-
# Returns a hash of all the attributes that have been specified for
|
18
|
-
# serialization as keys and their class restriction as values.
|
19
|
-
|
20
9
|
# If you have an attribute that needs to be saved to the database as an
|
21
10
|
# object, and retrieved as the same object, then specify the name of that
|
22
11
|
# attribute using this method and it will be handled automatically. The
|
23
12
|
# serialization is done through YAML. If +class_name+ is specified, the
|
24
|
-
# serialized object must be of that class on retrieval
|
25
|
-
# <tt>SerializationTypeMismatch</tt> will be raised.
|
26
|
-
#
|
27
|
-
# A notable side effect of serialized attributes is that the model will
|
28
|
-
# be updated on every save, even if it is not dirty.
|
13
|
+
# serialized object must be of that class on assignment and retrieval.
|
14
|
+
# Otherwise <tt>SerializationTypeMismatch</tt> will be raised.
|
29
15
|
#
|
30
16
|
# ==== Parameters
|
31
17
|
#
|
@@ -50,8 +36,6 @@ module ActiveRecord
|
|
50
36
|
# serialize :preferences, Hash
|
51
37
|
# end
|
52
38
|
def serialize(attr_name, class_name_or_coder = Object)
|
53
|
-
include Behavior
|
54
|
-
|
55
39
|
# When ::JSON is used, force it to go through the Active Support JSON encoder
|
56
40
|
# to ensure special objects (e.g. Active Record models) are dumped correctly
|
57
41
|
# using the #as_json hook.
|
@@ -63,140 +47,22 @@ module ActiveRecord
|
|
63
47
|
Coders::YAMLColumn.new(class_name_or_coder)
|
64
48
|
end
|
65
49
|
|
66
|
-
|
67
|
-
|
68
|
-
self.serialized_attributes = serialized_attributes.merge(attr_name.to_s => coder)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class Type # :nodoc:
|
73
|
-
def initialize(column)
|
74
|
-
@column = column
|
75
|
-
end
|
76
|
-
|
77
|
-
def type_cast(value)
|
78
|
-
if value.state == :serialized
|
79
|
-
value.unserialized_value @column.type_cast value.value
|
80
|
-
else
|
81
|
-
value.unserialized_value
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def type
|
86
|
-
@column.type
|
87
|
-
end
|
88
|
-
|
89
|
-
def accessor
|
90
|
-
ActiveRecord::Store::IndifferentHashAccessor
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
class Attribute < Struct.new(:coder, :value, :state) # :nodoc:
|
95
|
-
def unserialized_value(v = value)
|
96
|
-
state == :serialized ? unserialize(v) : value
|
97
|
-
end
|
98
|
-
|
99
|
-
def serialized_value
|
100
|
-
state == :unserialized ? serialize : value
|
101
|
-
end
|
102
|
-
|
103
|
-
def unserialize(v)
|
104
|
-
self.state = :unserialized
|
105
|
-
self.value = coder.load(v)
|
106
|
-
end
|
107
|
-
|
108
|
-
def serialize
|
109
|
-
self.state = :serialized
|
110
|
-
self.value = coder.dump(value)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# This is only added to the model when serialize is called, which
|
115
|
-
# ensures we do not make things slower when serialization is not used.
|
116
|
-
module Behavior # :nodoc:
|
117
|
-
extend ActiveSupport::Concern
|
118
|
-
|
119
|
-
module ClassMethods # :nodoc:
|
120
|
-
def initialize_attributes(attributes, options = {})
|
121
|
-
serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized
|
122
|
-
super(attributes, options)
|
123
|
-
|
124
|
-
serialized_attributes.each do |key, coder|
|
125
|
-
if attributes.key?(key)
|
126
|
-
attributes[key] = Attribute.new(coder, attributes[key], serialized)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
attributes
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def should_record_timestamps?
|
135
|
-
super || (self.record_timestamps && (attributes.keys & self.class.serialized_attributes.keys).present?)
|
136
|
-
end
|
137
|
-
|
138
|
-
def keys_for_partial_write
|
139
|
-
super | (attributes.keys & self.class.serialized_attributes.keys)
|
140
|
-
end
|
141
|
-
|
142
|
-
def type_cast_attribute_for_write(column, value)
|
143
|
-
if column && coder = self.class.serialized_attributes[column.name]
|
144
|
-
Attribute.new(coder, value, :unserialized)
|
145
|
-
else
|
146
|
-
super
|
50
|
+
decorate_attribute_type(attr_name, :serialize) do |type|
|
51
|
+
Type::Serialized.new(type, coder)
|
147
52
|
end
|
148
53
|
end
|
149
54
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
end
|
156
|
-
end
|
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
|
157
60
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def read_attribute_before_type_cast(attr_name)
|
167
|
-
if self.class.serialized_attributes.include?(attr_name)
|
168
|
-
super.unserialized_value
|
169
|
-
else
|
170
|
-
super
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def attributes_before_type_cast
|
175
|
-
super.dup.tap do |attributes|
|
176
|
-
self.class.serialized_attributes.each_key do |key|
|
177
|
-
if attributes.key?(key)
|
178
|
-
attributes[key] = attributes[key].unserialized_value
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def typecasted_attribute_value(name)
|
185
|
-
if self.class.serialized_attributes.include?(name)
|
186
|
-
@attributes[name].serialized_value
|
187
|
-
else
|
188
|
-
super
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def attributes_for_coder
|
193
|
-
attribute_names.each_with_object({}) do |name, attrs|
|
194
|
-
attrs[name] = if self.class.serialized_attributes.include?(name)
|
195
|
-
@attributes[name].serialized_value
|
196
|
-
else
|
197
|
-
read_attribute(name)
|
198
|
-
end
|
199
|
-
end
|
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
|
+
]
|
200
66
|
end
|
201
67
|
end
|
202
68
|
end
|
@@ -1,18 +1,33 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module AttributeMethods
|
3
3
|
module TimeZoneConversion
|
4
|
-
class Type # :nodoc:
|
5
|
-
|
6
|
-
|
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)
|
7
9
|
end
|
8
10
|
|
9
|
-
def
|
10
|
-
value
|
11
|
-
|
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
|
12
21
|
end
|
13
22
|
|
14
|
-
def
|
15
|
-
|
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
|
16
31
|
end
|
17
32
|
end
|
18
33
|
|
@@ -27,43 +42,26 @@ module ActiveRecord
|
|
27
42
|
end
|
28
43
|
|
29
44
|
module ClassMethods
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
EOV
|
44
|
-
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
45
|
-
else
|
46
|
-
super
|
45
|
+
private
|
46
|
+
|
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)
|
56
|
+
end
|
47
57
|
end
|
58
|
+
super
|
48
59
|
end
|
49
60
|
|
50
|
-
|
51
|
-
def create_time_zone_conversion_attribute?(name, column)
|
61
|
+
def create_time_zone_conversion_attribute?(name, cast_type)
|
52
62
|
time_zone_aware_attributes &&
|
53
63
|
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
|
54
|
-
(:datetime ==
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def convert_value_to_time_zone(attr_name, value)
|
61
|
-
if value.is_a?(Array)
|
62
|
-
value.map { |v| convert_value_to_time_zone(attr_name, v) }
|
63
|
-
elsif value.respond_to?(:in_time_zone)
|
64
|
-
value.in_time_zone || self.class.columns_hash[attr_name].type_cast(value)
|
65
|
-
else
|
66
|
-
nil
|
64
|
+
(:datetime == cast_type.type)
|
67
65
|
end
|
68
66
|
end
|
69
67
|
end
|