aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb51
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb10
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/model_schema.rb8
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb4
-rw-r--r--activerecord/lib/active_record/result.rb2
-rw-r--r--activerecord/lib/active_record/type/binary.rb9
-rw-r--r--activerecord/lib/active_record/type/serialized.rb10
-rw-r--r--activerecord/lib/active_record/type/value.rb23
20 files changed, 82 insertions, 85 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index c5f7bcae7d..306588ac66 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -57,7 +57,7 @@ module ActiveRecord
def ids_writer(ids)
pk_column = reflection.primary_key_column
ids = Array(ids).reject { |id| id.blank? }
- ids.map! { |i| pk_column.type_cast(i) }
+ ids.map! { |i| pk_column.type_cast_from_user(i) }
replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
end
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index 954128064d..f6e08991f7 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -89,7 +89,7 @@ module ActiveRecord
end
def through_scope_attributes
- scope.where_values_hash(through_association.reflection.name.to_s)
+ scope.where_values_hash(through_association.reflection.name.to_s).except!(through_association.reflection.foreign_key)
end
def save_through_record(record)
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 35659766d3..fbb4551b22 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -144,7 +144,7 @@ module ActiveRecord
column_aliases = aliases.column_aliases join_root
result_set.each { |row_hash|
- primary_id = type_caster.type_cast row_hash[primary_key]
+ primary_id = type_caster.type_cast_from_database row_hash[primary_key]
parent = parents[primary_id] ||= join_root.instantiate(row_hash, column_aliases)
construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
}
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index ae3785638a..a354cd7503 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -123,9 +123,9 @@ module ActiveRecord
}
if self.class.cache_attribute?(name)
- @attributes[name] = column.type_cast(value)
+ @attributes[name] = column.type_cast_from_database(value)
else
- column.type_cast value
+ column.type_cast_from_database value
end
}
end
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index c1c3987cf5..abad949ef4 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -1,21 +1,22 @@
module ActiveRecord
module AttributeMethods
module TimeZoneConversion
- class Type # :nodoc:
- delegate :type, :type_cast_for_database, to: :@column
-
- def initialize(column)
- @column = column
+ class Type < SimpleDelegator # :nodoc:
+ def type_cast_from_database(value)
+ convert_time_to_time_zone(super)
end
- def type_cast(value)
- value = @column.type_cast(value)
- convert_value_to_time_zone(value)
+ def type_cast_from_user(value)
+ if value.is_a?(Array)
+ value.map { |v| type_cast_from_user(v) }
+ elsif value.respond_to?(:in_time_zone)
+ value.in_time_zone
+ end
end
- def convert_value_to_time_zone(value)
+ def convert_time_to_time_zone(value)
if value.is_a?(Array)
- value.map { |v| convert_value_to_time_zone(v) }
+ value.map { |v| convert_time_to_time_zone(v) }
elsif value.acts_like?(:time)
value.in_time_zone
else
@@ -35,26 +36,6 @@ module ActiveRecord
end
module ClassMethods
- protected
- # Defined for all +datetime+ attributes when +time_zone_aware_attributes+ are enabled.
- # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone.
- def define_method_attribute=(attr_name)
- if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
- method_body, line = <<-EOV, __LINE__ + 1
- def #{attr_name}=(time)
- time_with_zone = convert_value_to_time_zone(time)
- previous_time = attribute_changed?("#{attr_name}") ? changed_attributes["#{attr_name}"] : read_attribute(:#{attr_name})
- write_attribute(:#{attr_name}, time)
- #{attr_name}_will_change! if previous_time != time_with_zone
- @attributes["#{attr_name}"] = time_with_zone
- end
- EOV
- generated_attribute_methods.module_eval(method_body, __FILE__, line)
- else
- super
- end
- end
-
private
def create_time_zone_conversion_attribute?(name, column)
time_zone_aware_attributes &&
@@ -62,16 +43,6 @@ module ActiveRecord
(:datetime == column.type)
end
end
-
- private
-
- def convert_value_to_time_zone(value)
- if value.is_a?(Array)
- value.map { |v| convert_value_to_time_zone(v) }
- elsif value.respond_to?(:in_time_zone)
- value.in_time_zone
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 5203b30462..b72a6219b0 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -70,7 +70,7 @@ module ActiveRecord
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
@attributes.delete(attr_name)
- column = column_for_attribute(attr_name)
+ column = type_for_attribute(attr_name)
unless has_attribute?(attr_name) || self.class.columns_hash.key?(attr_name)
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
@@ -80,13 +80,11 @@ module ActiveRecord
# so we don't attempt to typecast multiple times.
if column.binary?
@attributes[attr_name] = value
+ elsif should_type_cast
+ @attributes[attr_name] = column.type_cast_from_user(value)
end
- if should_type_cast
- @raw_attributes[attr_name] = column.type_cast_for_write(value)
- else
- @raw_attributes[attr_name] = value
- end
+ @raw_attributes[attr_name] = value
end
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index e8c067f758..e4d0abb8ef 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -311,8 +311,8 @@ module ActiveRecord #:nodoc:
include Locking::Optimistic
include Locking::Pessimistic
include AttributeMethods
- include Timestamp
include Callbacks
+ include Timestamp
include Associations
include ActiveModel::SecurePassword
include AutosaveAssociation
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 23434df1fe..72c6990ba5 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -17,7 +17,7 @@ module ActiveRecord
delegate :type, :precision, :scale, :limit, :klass, :accessor,
:text?, :number?, :binary?, :serialized?, :changed?,
- :type_cast, :type_cast_for_write, :type_cast_for_database,
+ :type_cast_from_user, :type_cast_from_database, :type_cast_for_database,
:type_cast_for_schema,
to: :cast_type
@@ -52,7 +52,7 @@ module ActiveRecord
end
def default
- @default ||= type_cast(@original_default)
+ @default ||= type_cast_from_database(@original_default)
end
def with_type(type)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index 971f5eed7e..666d1cf6e3 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -108,7 +108,7 @@ module ActiveRecord
if ::Array === value
value.map {|item| type_cast_array(oid, item)}
else
- oid.type_cast value
+ oid.type_cast_from_database value
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
index a65ca83f77..88de816d4f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
@@ -7,12 +7,16 @@ module ActiveRecord
:hstore
end
- def type_cast_for_write(value)
- ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value)
+ def type_cast_from_user(value)
+ type_cast_from_database(type_cast_for_database(value))
+ end
+
+ def type_cast_from_database(value)
+ ConnectionAdapters::PostgreSQLColumn.string_to_hstore(value)
end
- def cast_value(value)
- ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
+ def type_cast_for_database(value)
+ ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value)
end
def accessor
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
index c87422fe32..b4fed1bcab 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
@@ -7,12 +7,16 @@ module ActiveRecord
:json
end
- def type_cast_for_write(value)
- ConnectionAdapters::PostgreSQLColumn.json_to_string(value)
+ def type_cast_from_user(value)
+ type_cast_from_database(type_cast_for_database(value))
+ end
+
+ def type_cast_from_database(value)
+ ConnectionAdapters::PostgreSQLColumn.string_to_json(value)
end
- def cast_value(value)
- ConnectionAdapters::PostgreSQLColumn.string_to_json value
+ def type_cast_for_database(value)
+ ConnectionAdapters::PostgreSQLColumn.json_to_string(value)
end
def accessor
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index a0d8a94c74..c289ba8980 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -29,7 +29,7 @@ module ActiveRecord
end
def type_cast_single(value)
- infinity?(value) ? value : @subtype.type_cast(value)
+ infinity?(value) ? value : @subtype.type_cast_from_database(value)
end
def cast_value(value)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 283ca81f94..71b05cdbae 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -348,14 +348,14 @@ module ActiveRecord
if supports_extensions?
res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
'SCHEMA'
- res.column_types['enabled'].type_cast res.rows.first.first
+ res.column_types['enabled'].type_cast_from_database res.rows.first.first
end
end
def extensions
if supports_extensions?
res = exec_query "SELECT extname from pg_extension", "SCHEMA"
- res.rows.map { |r| res.column_types['extname'].type_cast r.first }
+ res.rows.map { |r| res.column_types['extname'].type_cast_from_database r.first }
else
super
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index baf2b5fbf8..f96f77f696 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -51,6 +51,8 @@ module ActiveRecord
self.pluralize_table_names = true
self.inheritance_column = 'type'
+
+ delegate :type_for_attribute, to: :class
end
module ClassMethods
@@ -221,6 +223,10 @@ module ActiveRecord
@column_types ||= decorate_columns(columns_hash.dup)
end
+ def type_for_attribute(attr_name) # :nodoc:
+ column_types.fetch(attr_name) { column_for_attribute(attr_name) }
+ end
+
def decorate_columns(columns_hash) # :nodoc:
return if columns_hash.empty?
@@ -245,7 +251,7 @@ module ActiveRecord
# are the default values suitable for use in `@raw_attriubtes`
def raw_column_defaults # :nodoc:
@raw_column_defauts ||= Hash[column_defaults.map { |name, default|
- [name, columns_hash[name].type_cast_for_write(default)]
+ [name, columns_hash[name].type_cast_for_database(default)]
}]
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 1242f49e28..8a2a06f2ca 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -516,7 +516,7 @@ module ActiveRecord
# Determines if a hash contains a truthy _destroy key.
def has_destroy_flag?(hash)
- Type::Boolean.new.type_cast(hash['_destroy'])
+ Type::Boolean.new.type_cast_from_user(hash['_destroy'])
end
# Determines if a new record should be rejected by checking
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 11ab1b4595..38970a66ae 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -179,7 +179,7 @@ module ActiveRecord
result = result.map do |attributes|
values = attributes.values
- columns.zip(values).map { |column, value| column.type_cast value }
+ columns.zip(values).map { |column, value| column.type_cast_from_database value }
end
columns.one? ? result.map!(&:first) : result
end
@@ -379,7 +379,7 @@ module ActiveRecord
end
def type_cast_using_column(value, column)
- column ? column.type_cast(value) : value
+ column ? column.type_cast_from_database(value) : value
end
# TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index 293189fa69..ae53f66d7a 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -31,7 +31,7 @@ module ActiveRecord
class Result
include Enumerable
- IDENTITY_TYPE = Class.new { def type_cast(v); v; end }.new # :nodoc:
+ IDENTITY_TYPE = Type::Value.new # :nodoc:
attr_reader :columns, :rows, :column_types
diff --git a/activerecord/lib/active_record/type/binary.rb b/activerecord/lib/active_record/type/binary.rb
index bc93f6e1bf..3bf29b5026 100644
--- a/activerecord/lib/active_record/type/binary.rb
+++ b/activerecord/lib/active_record/type/binary.rb
@@ -9,7 +9,16 @@ module ActiveRecord
true
end
+ def type_cast(value)
+ if value.is_a?(Data)
+ value.to_s
+ else
+ super
+ end
+ end
+
def type_cast_for_database(value)
+ return if value.nil?
Data.new(super)
end
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index 0866383de9..9144028576 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -9,7 +9,7 @@ module ActiveRecord
super(subtype)
end
- def type_cast(value)
+ def type_cast_from_database(value)
if is_default_value?(value)
value
else
@@ -17,15 +17,17 @@ module ActiveRecord
end
end
- def type_cast_for_write(value)
+ def type_cast_from_user(value)
+ type_cast_from_database(type_cast_for_database(value))
+ end
+
+ def type_cast_for_database(value)
return if value.nil?
unless is_default_value?(value)
super coder.dump(value)
end
end
- alias type_cast_for_database type_cast_for_write
-
def serialized?
true
end
diff --git a/activerecord/lib/active_record/type/value.rb b/activerecord/lib/active_record/type/value.rb
index 1c41b28646..efcdab1c0e 100644
--- a/activerecord/lib/active_record/type/value.rb
+++ b/activerecord/lib/active_record/type/value.rb
@@ -16,15 +16,16 @@ module ActiveRecord
# must override this method.
def type; end
- # Takes an input from the database, or from attribute setters,
- # and casts it to a type appropriate for this object. This method
- # should not be overriden by subclasses. Instead, override `cast_value`.
- def type_cast(value)
- cast_value(value) unless value.nil?
+ def type_cast_from_database(value)
+ type_cast(value)
+ end
+
+ def type_cast_from_user(value)
+ type_cast(value)
end
def type_cast_for_database(value)
- type_cast_for_write(value)
+ value
end
def type_cast_for_schema(value)
@@ -50,10 +51,6 @@ module ActiveRecord
def klass # :nodoc:
end
- def type_cast_for_write(value) # :nodoc:
- value
- end
-
# +old_value+ will always be type-cast.
# +new_value+ will come straight from the database
# or from assignment, so it could be anything. Types
@@ -64,6 +61,12 @@ module ActiveRecord
end
private
+ # Takes an input from the database, or from attribute setters,
+ # and casts it to a type appropriate for this object. This method
+ # should not be overriden by subclasses. Instead, override `cast_value`.
+ def type_cast(value) # :api: public
+ cast_value(value) unless value.nil?
+ end
# Responsible for casting values from external sources to the appropriate
# type. Called by `type_cast` for all values except `nil`.