aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md26
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb15
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/has_one.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb10
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb49
-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/autosave_association.rb2
-rw-r--r--activerecord/lib/active_record/base.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb30
-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/core.rb1
-rw-r--r--activerecord/lib/active_record/fixtures.rb12
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb6
-rw-r--r--activerecord/lib/active_record/model_schema.rb22
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/querying.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb35
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb8
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/lib/active_record/result.rb2
-rw-r--r--activerecord/lib/active_record/timestamp.rb8
-rw-r--r--activerecord/lib/active_record/type/binary.rb9
-rw-r--r--activerecord/lib/active_record/type/serialized.rb21
-rw-r--r--activerecord/lib/active_record/type/value.rb23
-rw-r--r--activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/composite_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb46
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/money_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb2
-rw-r--r--activerecord/test/cases/attribute_decorators_test.rb4
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb44
-rw-r--r--activerecord/test/cases/base_test.rb2
-rw-r--r--activerecord/test/cases/calculations_test.rb7
-rw-r--r--activerecord/test/cases/connection_adapters/type_lookup_test.rb2
-rw-r--r--activerecord/test/cases/dirty_test.rb6
-rw-r--r--activerecord/test/cases/finder_test.rb11
-rw-r--r--activerecord/test/cases/fixtures_test.rb6
-rw-r--r--activerecord/test/cases/locking_test.rb4
-rw-r--r--activerecord/test/cases/reflection_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb2
-rw-r--r--activerecord/test/cases/timestamp_test.rb31
-rw-r--r--activerecord/test/cases/types_test.rb138
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb15
-rw-r--r--activerecord/test/schema/schema.rb1
62 files changed, 391 insertions, 402 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e7e414571d..e0a7552921 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,25 @@
+* Pluck now works when selecting columns from different tables with the same
+ name.
+
+ Fixes #15649
+
+ *Sean Griffin*
+
+* Remove `cache_attributes` and friends. All attributes are cached.
+
+ *Sean Griffin*
+
+* Remove deprecated method `ActiveRecord::Base.quoted_locking_column`.
+
+ *Akshay Vishnoi*
+
+* `ActiveRecord::FinderMethods.find` with block can handle proc parameter as
+ `Enumerable#find` does.
+
+ Fixes #15382.
+
+ *James Yang*
+
* Make timezone aware attributes work with PostgreSQL array columns.
Fixes #13402.
@@ -532,10 +554,6 @@
*Luke Steensen*
-* Make possible to change `record_timestamps` inside Callbacks.
-
- *Tieg Zaharia*
-
* Fixed error where .persisted? throws SystemStackError for an unsaved model with a
custom primary key that didn't save due to validation error.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 07dfc448e7..6222bfe903 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1577,7 +1577,7 @@ module ActiveRecord
scope = nil
end
- habtm_reflection = ActiveRecord::Reflection::AssociationReflection.new(:has_and_belongs_to_many, name, scope, options, self)
+ habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(:has_and_belongs_to_many, name, scope, options, self)
builder = Builder::HasAndBelongsToMany.new name, self, options
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 4a04303fb8..f1c36cd047 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -179,7 +179,7 @@ module ActiveRecord
def creation_attributes
attributes = {}
- if (reflection.macro == :has_one || reflection.macro == :has_many) && !options[:through]
+ if (reflection.has_one? || reflection.collection?) && !options[:through]
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
if reflection.options[:as]
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 31108cc1aa..519d4d8651 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -105,18 +105,9 @@ module ActiveRecord
chain.each_with_index do |reflection, i|
table, foreign_table = tables.shift, tables.first
- if reflection.source_macro == :belongs_to
- if reflection.polymorphic?
- key = reflection.association_primary_key(assoc_klass)
- else
- key = reflection.association_primary_key
- end
-
- foreign_key = reflection.foreign_key
- else
- key = reflection.foreign_key
- foreign_key = reflection.active_record_primary_key
- end
+ join_keys = reflection.join_keys(assoc_klass)
+ key = join_keys.key
+ foreign_key = join_keys.foreign_key
if reflection == chain.last
bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key], tracker
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 1edd4fa3aa..81fdd681de 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -92,7 +92,7 @@ module ActiveRecord
# has_one associations.
def invertible_for?(record)
inverse = inverse_reflection_for(record)
- inverse && inverse.macro == :has_one
+ inverse && inverse.has_one?
end
def target_id
diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb
index f359efd496..a1f4f51664 100644
--- a/activerecord/lib/active_record/associations/builder/has_one.rb
+++ b/activerecord/lib/active_record/associations/builder/has_one.rb
@@ -5,7 +5,7 @@ module ActiveRecord::Associations::Builder
end
def valid_options
- valid = super + [:order, :as]
+ valid = super + [:as]
valid += [:through, :source, :source_type] if options[:through]
valid
end
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..da9b125fd6 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)
@@ -105,9 +105,9 @@ module ActiveRecord
inverse = source_reflection.inverse_of
if inverse
- if inverse.macro == :has_many
+ if inverse.collection?
record.send(inverse.name) << build_through_record(record)
- elsif inverse.macro == :has_one
+ elsif inverse.has_one?
record.send("#{inverse.name}=", build_through_record(record))
end
end
@@ -170,7 +170,7 @@ module ActiveRecord
klass.decrement_counter counter, records.map(&:id)
end
- if through_reflection.macro == :has_many && update_through_counter?(method)
+ if through_reflection.collection? && update_through_counter?(method)
update_counter(-count, through_reflection)
end
@@ -187,7 +187,7 @@ module ActiveRecord
records.each do |record|
through_records = through_records_for(record)
- if through_reflection.macro == :has_many
+ if through_reflection.collection?
through_records.each { |r| through_association.target.delete(r) }
else
if through_records.include?(through_association.target)
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..7b7e37884b 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -35,35 +35,22 @@ module ActiveRecord
extend ActiveSupport::Concern
- ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :time, :date]
-
- included do
- class_attribute :attribute_types_cached_by_default, instance_writer: false
- self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
- end
-
module ClassMethods
- # +cache_attributes+ allows you to declare which converted attribute
- # values should be cached. Usually caching only pays off for attributes
- # with expensive conversion methods, like time related columns (e.g.
- # +created_at+, +updated_at+).
- def cache_attributes(*attribute_names)
- cached_attributes.merge attribute_names.map { |attr| attr.to_s }
+ [:cache_attributes, :cached_attributes, :cache_attribute?].each do |method_name|
+ define_method method_name do |*|
+ cached_attributes_deprecation_warning(method_name)
+ true
+ end
end
- # Returns the attributes which are cached. By default time related columns
- # with datatype <tt>:datetime, :time, :date</tt> are cached.
- def cached_attributes
- @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set
- end
+ protected
- # Returns +true+ if the provided attribute is being cached.
- def cache_attribute?(attr_name)
- cached_attributes.include?(attr_name)
+ def cached_attributes_deprecation_warning(method_name)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ Calling `#{method_name}` is no longer necessary. All attributes are cached.
+ MESSAGE
end
- protected
-
if Module.methods_transplantable?
def define_method_attribute(name)
method = ReaderMethodCache[name]
@@ -89,16 +76,6 @@ module ActiveRecord
end
end
end
-
- private
-
- def cacheable_column?(column)
- if attribute_types_cached_by_default == ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
- true
- else
- attribute_types_cached_by_default.include?(column.type)
- end
- end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after
@@ -122,11 +99,7 @@ module ActiveRecord
return block_given? ? yield(name) : nil
}
- if self.class.cache_attribute?(name)
- @attributes[name] = column.type_cast(value)
- else
- column.type_cast value
- end
+ @attributes[name] = column.type_cast_from_database(value)
}
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/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 74e2a8e6b9..b3c3e26c9f 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -187,7 +187,7 @@ module ActiveRecord
# Doesn't use after_save as that would save associations added in after_create/after_update twice
after_create save_method
after_update save_method
- elsif reflection.macro == :has_one
+ elsif reflection.has_one?
define_method(save_method) { save_has_one_association(reflection) } unless method_defined?(save_method)
# Configures two callbacks instead of a single after_save so that
# the model may rely on their execution order relative to its
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/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index d3e172927d..5a0efe49c7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -1,5 +1,3 @@
-require 'ipaddr'
-
module ActiveRecord
module ConnectionAdapters # :nodoc:
# The goal of this module is to move Adapter specific column
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..bb54de05c8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -67,10 +67,6 @@ module ActiveRecord
end
end
- def string_to_array(string, oid) # :nodoc:
- parse_pg_array(string).map {|val| type_cast_array(oid, val)}
- end
-
private
HstorePair = begin
@@ -103,14 +99,6 @@ module ActiveRecord
"\"#{value}\""
end
end
-
- def type_cast_array(oid, value)
- if ::Array === value
- value.map {|item| type_cast_array(oid, item)}
- else
- oid.type_cast value
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index a579746815..847fd4dded 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -4,6 +4,8 @@ module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
+ extend PostgreSQL::Cast
+
attr_accessor :array
def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
@@ -17,24 +19,6 @@ module ActiveRecord
@default_function = default_function
end
-
- # :stopdoc:
- class << self
- include PostgreSQL::Cast
-
- # Loads pg_array_parser if available. String parsing can be
- # performed quicker by a native extension, which will not create
- # a large amount of Ruby objects that will need to be garbage
- # collected. pg_array_parser has a C and Java extension
- begin
- require 'pg_array_parser'
- include PgArrayParser
- rescue LoadError
- require 'active_record/connection_adapters/postgresql/array_parser'
- include PostgreSQL::ArrayParser
- end
- end
- # :startdoc:
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 0e9dcd8c0c..87817fe8d1 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -10,11 +10,33 @@ module ActiveRecord
@subtype = subtype
end
- def type_cast(value)
- if ::String === value
- ConnectionAdapters::PostgreSQLColumn.string_to_array value, @subtype
+ def type_cast_from_database(value)
+ if value.is_a?(::String)
+ type_cast_array(parse_pg_array(value))
else
- value
+ super
+ end
+ end
+
+ # Loads pg_array_parser if available. String parsing can be
+ # performed quicker by a native extension, which will not create
+ # a large amount of Ruby objects that will need to be garbage
+ # collected. pg_array_parser has a C and Java extension
+ begin
+ require 'pg_array_parser'
+ include PgArrayParser
+ rescue LoadError
+ require 'active_record/connection_adapters/postgresql/array_parser'
+ include PostgreSQL::ArrayParser
+ end
+
+ private
+
+ def type_cast_array(value)
+ if value.is_a?(::Array)
+ value.map { |item| type_cast_array(item) }
+ else
+ @subtype.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/core.rb b/activerecord/lib/active_record/core.rb
index 79388f53b5..7edaf256c7 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -356,6 +356,7 @@ module ActiveRecord
def encode_with(coder)
coder['raw_attributes'] = @raw_attributes
coder['attributes'] = @attributes
+ coder['column_types'] = @column_types_override
coder['new_record'] = new_record?
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 6ba667b996..95fcbbe99a 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -462,13 +462,7 @@ module ActiveRecord
@config = config
# Remove string values that aren't constants or subclasses of AR
- @class_names.delete_if { |k,klass|
- unless klass.is_a? Class
- klass = klass.safe_constantize
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `set_fixture_class` will be removed in Rails 4.2. Use the class itself instead.")
- end
- !insert_class(@class_names, k, klass)
- }
+ @class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
end
def [](fs_name)
@@ -574,10 +568,6 @@ module ActiveRecord
@config = config
@model_class = nil
- if class_name.is_a?(String)
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `FixtureSet.new` will be removed in Rails 4.2. Use the class itself instead.")
- end
-
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
@model_class = class_name
else
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index f7ceff7469..4528d8783c 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -151,12 +151,6 @@ module ActiveRecord
@locking_column
end
- # Quote the column name used for optimistic locking.
- def quoted_locking_column
- ActiveSupport::Deprecation.warn "ActiveRecord::Base.quoted_locking_column is deprecated and will be removed in Rails 4.2 or later."
- connection.quote_column_name(locking_column)
- end
-
# Reset the column used for optimistic locking back to the +lock_version+ default.
def reset_locking_column
self.locking_column = DEFAULT_LOCKING_COLUMN
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index baf2b5fbf8..9e1afd32e6 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
@@ -218,21 +220,25 @@ module ActiveRecord
end
def column_types # :nodoc:
- @column_types ||= decorate_columns(columns_hash.dup)
+ @column_types ||= decorate_types(build_types_hash)
+ end
+
+ def type_for_attribute(attr_name) # :nodoc:
+ column_types.fetch(attr_name) { Type::Value.new }
end
- def decorate_columns(columns_hash) # :nodoc:
- return if columns_hash.empty?
+ def decorate_types(types) # :nodoc:
+ return if types.empty?
@time_zone_column_names ||= self.columns_hash.find_all do |name, col|
create_time_zone_conversion_attribute?(name, col)
end.map!(&:first)
@time_zone_column_names.each do |name|
- columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(columns_hash[name])
+ types[name] = AttributeMethods::TimeZoneConversion::Type.new(types[name])
end
- columns_hash
+ types
end
# Returns a hash where the keys are column names and the values are
@@ -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
@@ -329,6 +335,10 @@ module ActiveRecord
base.table_name
end
end
+
+ def build_types_hash
+ Hash[columns.map { |column| [column.name, column.cast_type] }]
+ end
end
end
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/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 525289c270..3ab8ec4836 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -48,7 +48,6 @@ module ActiveRecord
# how this "single-table" inheritance mapping is implemented.
def instantiate(attributes, column_types = {})
klass = discriminate_class_for_record(attributes)
- column_types = klass.decorate_columns(column_types.dup)
klass.allocate.init_with(
'raw_attributes' => attributes,
'column_types' => column_types,
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index 1fe54cea3f..39817703cd 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -40,7 +40,7 @@ module ActiveRecord
column_types = {}
if result_set.respond_to? :column_types
- column_types = result_set.column_types.merge(columns_hash)
+ column_types = result_set.column_types.except(*columns_hash.keys)
else
ActiveSupport::Deprecation.warn "the object returned from `select_all` must respond to `column_types`"
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 4d5203612c..95a3c70c93 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -188,6 +188,23 @@ module ActiveRecord
active_record == other_aggregation.active_record
end
+ JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
+
+ def join_keys(assoc_klass)
+ if source_macro == :belongs_to
+ if polymorphic?
+ reflection_key = association_primary_key(assoc_klass)
+ else
+ reflection_key = association_primary_key
+ end
+ reflection_foreign_key = foreign_key
+ else
+ reflection_key = foreign_key
+ reflection_foreign_key = active_record_primary_key
+ end
+ JoinKeys.new(reflection_key, reflection_foreign_key)
+ end
+
private
def derive_class_name
name.to_s.camelize
@@ -228,7 +245,7 @@ module ActiveRecord
def initialize(macro, name, scope, options, active_record)
super
- @collection = [:has_many, :has_and_belongs_to_many].include?(macro)
+ @collection = macro == :has_many
@automatic_inverse_of = nil
@type = options[:as] && "#{options[:as]}_type"
@foreign_type = options[:foreign_type] || "#{name}_type"
@@ -392,7 +409,7 @@ Joining, Preloading and eager loading of these associations is deprecated and wi
# * you use autosave; <tt>autosave: true</tt>
# * the association is a +has_many+ association
def validate?
- !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
+ !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
end
# Returns +true+ if +self+ is a +belongs_to+ reflection.
@@ -400,6 +417,11 @@ Joining, Preloading and eager loading of these associations is deprecated and wi
macro == :belongs_to
end
+ # Returns +true+ if +self+ is a +has_one+ reflection.
+ def has_one?
+ macro == :has_one
+ end
+
def association_class
case macro
when :belongs_to
@@ -538,6 +560,13 @@ Joining, Preloading and eager loading of these associations is deprecated and wi
end
end
+ class HasAndBelongsToManyReflection < AssociationReflection #:nodoc:
+ def initialize(macro, name, scope, options, active_record)
+ super
+ @collection = true
+ end
+ end
+
# Holds all the meta-data about a :through association as it was specified
# in the Active Record class.
class ThroughReflection < AssociationReflection #:nodoc:
@@ -739,7 +768,7 @@ directive on your declaration like:
raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
end
- if macro == :has_one && through_reflection.collection?
+ if has_one? && through_reflection.collection?
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 11ab1b4595..028e4d80ab 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -176,10 +176,8 @@ module ActiveRecord
}
end
- result = result.map do |attributes|
- values = attributes.values
-
- columns.zip(values).map { |column, value| column.type_cast value }
+ result = result.rows.map do |values|
+ columns.zip(values).map { |column, value| column.type_cast_from_database value }
end
columns.one? ? result.map!(&:first) : result
end
@@ -379,7 +377,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/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 47e90e9021..0c9c761f97 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -65,7 +65,7 @@ module ActiveRecord
# # returns an Array of the required fields, available since Rails 3.1.
def find(*args)
if block_given?
- to_a.find { |*block_args| yield(*block_args) }
+ to_a.find(*args) { |*block_args| yield(*block_args) }
else
find_with_ids(*args)
end
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/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index 6c30ccab72..e2e37e7c00 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -99,9 +99,11 @@ module ActiveRecord
end
def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update)
- if (timestamps = timestamp_names.map { |attr| self[attr] }.compact).present?
- timestamps.map { |ts| ts.to_time }.max
- end
+ timestamp_names
+ .map { |attr| self[attr] }
+ .compact
+ .map(&:to_time)
+ .max
end
def current_time_from_proper_timezone
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..e6d84eadc0 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
@@ -34,6 +36,17 @@ module ActiveRecord
ActiveRecord::Store::IndifferentHashAccessor
end
+ def init_with(coder)
+ @subtype = coder['subtype']
+ @coder = coder['coder']
+ __setobj__(@subtype)
+ end
+
+ def encode_with(coder)
+ coder['subtype'] = @subtype
+ coder['coder'] = @coder
+ end
+
private
def is_default_value?(value)
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`.
diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
index 1699380eb3..28106d3772 100644
--- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -105,7 +105,7 @@ module ActiveRecord
result = @conn.exec_query('SELECT status FROM ex')
- assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
+ assert_equal 2, result.column_types['status'].type_cast_from_database(result.last['status'])
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 1d431f1666..66750deb68 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -90,9 +90,9 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
end
def test_type_cast_array
- assert_equal(['1', '2', '3'], @column.type_cast('{1,2,3}'))
- assert_equal([], @column.type_cast('{}'))
- assert_equal([nil], @column.type_cast('{NULL}'))
+ assert_equal(['1', '2', '3'], @column.type_cast_from_database('{1,2,3}'))
+ assert_equal([], @column.type_cast_from_database('{}'))
+ assert_equal([nil], @column.type_cast_from_database('{NULL}'))
end
def test_type_cast_integers
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
index 3f8a5d1062..7872f91943 100644
--- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -33,16 +33,16 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
data = "\u001F\x8B"
assert_equal('UTF-8', data.encoding.name)
- assert_equal('ASCII-8BIT', @column.type_cast(data).encoding.name)
+ assert_equal('ASCII-8BIT', @column.type_cast_from_database(data).encoding.name)
end
def test_type_cast_binary_value
data = "\u001F\x8B".force_encoding("BINARY")
- assert_equal(data, @column.type_cast(data))
+ assert_equal(data, @column.type_cast_from_database(data))
end
def test_type_case_nil
- assert_equal(nil, @column.type_cast(nil))
+ assert_equal(nil, @column.type_cast_from_database(nil))
end
def test_read_value
diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb
index a925263098..0b48fe9af8 100644
--- a/activerecord/test/cases/adapters/postgresql/composite_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb
@@ -90,7 +90,11 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase
end
end
- def type_cast_for_write(value)
+ def type_cast_from_user(value)
+ value
+ end
+
+ def type_cast_for_database(value)
return if value.nil?
"(#{value.city},#{value.street})"
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 5f84c893c0..d26cda46fa 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -121,7 +121,7 @@ module ActiveRecord
name = @subscriber.payloads.last[:statement_name]
assert name
res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(#{bindval})")
- plan = res.column_types['QUERY PLAN'].type_cast res.rows.first.first
+ plan = res.column_types['QUERY PLAN'].type_cast_from_database res.rows.first.first
assert_operator plan.length, :>, 0
end
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index a6482786c7..a25c9cb5e4 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -106,6 +106,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
def test_cast_value_on_write
x = Hstore.new tags: {"bool" => true, "number" => 5}
+ assert_equal({"bool" => true, "number" => 5}, x.tags_before_type_cast)
assert_equal({"bool" => "true", "number" => "5"}, x.tags)
x.save
assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags)
@@ -117,11 +118,11 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
data = "\"1\"=>\"2\""
hash = @column.class.string_to_hstore data
assert_equal({'1' => '2'}, hash)
- assert_equal({'1' => '2'}, @column.type_cast(data))
+ assert_equal({'1' => '2'}, @column.type_cast_from_database(data))
- assert_equal({}, @column.type_cast(""))
- assert_equal({'key'=>nil}, @column.type_cast('key => NULL'))
- assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b")))
+ assert_equal({}, @column.type_cast_from_database(""))
+ assert_equal({'key'=>nil}, @column.type_cast_from_database('key => NULL'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b")))
end
def test_with_store_accessors
@@ -179,31 +180,31 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
end
def test_parse1
- assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
+ assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast_from_database('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
end
def test_parse2
- assert_equal({" " => " "}, @column.type_cast("\\ =>\\ "))
+ assert_equal({" " => " "}, @column.type_cast_from_database("\\ =>\\ "))
end
def test_parse3
- assert_equal({"=" => ">"}, @column.type_cast("==>>"))
+ assert_equal({"=" => ">"}, @column.type_cast_from_database("==>>"))
end
def test_parse4
- assert_equal({"=a"=>"q=w"}, @column.type_cast('\=a=>q=w'))
+ assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('\=a=>q=w'))
end
def test_parse5
- assert_equal({"=a"=>"q=w"}, @column.type_cast('"=a"=>q\=w'))
+ assert_equal({"=a"=>"q=w"}, @column.type_cast_from_database('"=a"=>q\=w'))
end
def test_parse6
- assert_equal({"\"a"=>"q>w"}, @column.type_cast('"\"a"=>q>w'))
+ assert_equal({"\"a"=>"q>w"}, @column.type_cast_from_database('"\"a"=>q>w'))
end
def test_parse7
- assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w'))
+ assert_equal({"\"a"=>"q\"w"}, @column.type_cast_from_database('\"a=>q"w'))
end
def test_rewrite
@@ -295,24 +296,18 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
assert_equal({ }, hstore.reload.tags)
end
- # FIXME: remove this lambda once `serialize` no longer issues a db connection.
- LAZY_MODELS = lambda do
- return if defined?(TagCollection)
-
- class TagCollection
- def initialize(hash); @hash = hash end
- def to_hash; @hash end
- def self.load(hash); new(hash) end
- def self.dump(object); object.to_hash end
- end
+ class TagCollection
+ def initialize(hash); @hash = hash end
+ def to_hash; @hash end
+ def self.load(hash); new(hash) end
+ def self.dump(object); object.to_hash end
+ end
- class HstoreWithSerialize < Hstore
- serialize :tags, TagCollection
- end
+ class HstoreWithSerialize < Hstore
+ serialize :tags, TagCollection
end
def test_hstore_with_serialized_attributes
- LAZY_MODELS.call
HstoreWithSerialize.create! tags: TagCollection.new({"one" => "two"})
record = HstoreWithSerialize.first
assert_instance_of TagCollection, record.tags
@@ -323,7 +318,6 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
end
def test_clone_hstore_with_serialized_attributes
- LAZY_MODELS.call
HstoreWithSerialize.create! tags: TagCollection.new({"one" => "two"})
record = HstoreWithSerialize.first
dupe = record.dup
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 61d4e2b8ae..3ee8839823 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -68,6 +68,7 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
def test_cast_value_on_write
x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar}
+ assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast)
assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload)
x.save
assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload)
@@ -79,11 +80,11 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
data = "{\"a_key\":\"a_value\"}"
hash = column.class.string_to_json data
assert_equal({'a_key' => 'a_value'}, hash)
- assert_equal({'a_key' => 'a_value'}, column.type_cast(data))
+ assert_equal({'a_key' => 'a_value'}, column.type_cast_from_database(data))
- assert_equal({}, column.type_cast("{}"))
- assert_equal({'key'=>nil}, column.type_cast('{"key": null}'))
- assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast(%q({"c":"}", "\"a\"":"b \"a b"})))
+ assert_equal({}, column.type_cast_from_database("{}"))
+ assert_equal({'key'=>nil}, column.type_cast_from_database('{"key": null}'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, column.type_cast_from_database(%q({"c":"}", "\"a\"":"b \"a b"})))
end
def test_rewrite
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb
index 3e33477bff..bdfeedafab 100644
--- a/activerecord/test/cases/adapters/postgresql/money_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/money_test.rb
@@ -49,10 +49,10 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase
def test_money_type_cast
column = PostgresqlMoney.columns_hash['wealth']
- assert_equal(12345678.12, column.type_cast("$12,345,678.12"))
- assert_equal(12345678.12, column.type_cast("$12.345.678,12"))
- assert_equal(-1.15, column.type_cast("-$1.15"))
- assert_equal(-2.25, column.type_cast("($2.25)"))
+ assert_equal(12345678.12, column.type_cast_from_user("$12,345,678.12"))
+ assert_equal(12345678.12, column.type_cast_from_user("$12.345.678,12"))
+ assert_equal(-1.15, column.type_cast_from_user("-$1.15"))
+ assert_equal(-2.25, column.type_cast_from_user("($2.25)"))
end
def test_schema_dumping
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index 4d9cfe55f5..0f6e39322c 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -156,7 +156,7 @@ _SQL
assert_equal 0.5..0.7, @first_range.float_range
assert_equal 0.5...0.7, @second_range.float_range
assert_equal 0.5...Float::INFINITY, @third_range.float_range
- assert_equal (-Float::INFINITY...Float::INFINITY), @fourth_range.float_range
+ assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.float_range)
assert_nil @empty_range.float_range
end
diff --git a/activerecord/test/cases/attribute_decorators_test.rb b/activerecord/test/cases/attribute_decorators_test.rb
index f17cc02f53..35393753a2 100644
--- a/activerecord/test/cases/attribute_decorators_test.rb
+++ b/activerecord/test/cases/attribute_decorators_test.rb
@@ -12,9 +12,11 @@ module ActiveRecord
super(delegate)
end
- def type_cast(value)
+ def type_cast_from_user(value)
"#{super} #{@decoration}"
end
+
+ alias type_cast_from_database type_cast_from_user
end
setup do
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 139fe9c04b..a366caf875 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -517,43 +517,17 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
end
- def test_only_time_related_columns_are_meant_to_be_cached_by_default
- expected = %w(datetime time date).sort
- assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
- end
-
- def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
- default_attributes = Topic.cached_attributes
- Topic.cache_attributes :replies_count
- expected = default_attributes + ["replies_count"]
- assert_equal expected.sort, Topic.cached_attributes.sort
- Topic.instance_variable_set "@cached_attributes", nil
- end
-
- def test_cacheable_columns_are_actually_cached
- assert_equal cached_columns.sort, Topic.cached_attributes.sort
- end
-
- def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
- t = topics(:first)
- cache = t.instance_variable_get "@attributes"
-
- assert_not_nil cache
- assert cache.empty?
+ def test_deprecated_cache_attributes
+ assert_deprecated do
+ Topic.cache_attributes :replies_count
+ end
- all_columns = Topic.columns.map(&:name)
- uncached_columns = all_columns - cached_columns
+ assert_deprecated do
+ Topic.cached_attributes
+ end
- all_columns.each do |attr_name|
- attribute_gets_cached = Topic.cache_attribute?(attr_name)
- val = t.send attr_name unless attr_name == "type"
- if attribute_gets_cached
- assert cached_columns.include?(attr_name)
- assert_equal val, cache[attr_name]
- else
- assert uncached_columns.include?(attr_name)
- assert !cache.include?(attr_name)
- end
+ assert_deprecated do
+ Topic.cache_attribute? :replies_count
end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index fad51f4924..dc8f25b0e7 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1489,7 +1489,7 @@ class BasicsTest < ActiveRecord::TestCase
attrs.delete 'id'
typecast = Class.new {
- def type_cast value
+ def type_cast_from_database value
"t.lo"
end
}
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index dfc6a7ec67..222b1505a8 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -610,4 +610,11 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [1,2,3,4,5], taks_relation.pluck(:id)
assert_equal [false, true, true, true, true], taks_relation.pluck(:approved)
end
+
+ def test_pluck_columns_with_same_name
+ expected = [["The First Topic", "The Second Topic of the day"], ["The Third Topic of the day", "The Fourth Topic of the day"]]
+ actual = Topic.joins(:replies)
+ .pluck('topics.title', 'replies_topics.title')
+ assert_equal expected, actual
+ end
end
diff --git a/activerecord/test/cases/connection_adapters/type_lookup_test.rb b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
index 3958c3bfff..d5c1dc1e5d 100644
--- a/activerecord/test/cases/connection_adapters/type_lookup_test.rb
+++ b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
@@ -85,7 +85,7 @@ module ActiveRecord
cast_type = @connection.type_map.lookup(type)
assert_equal :decimal, cast_type.type
- assert_equal 2, cast_type.type_cast(2.1)
+ assert_equal 2, cast_type.type_cast_from_user(2.1)
end
end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 2beac84fb1..87f24e32b2 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -616,17 +616,15 @@ class DirtyTest < ActiveRecord::TestCase
end
end
- test "defaults with type that implements `type_cast_for_write`" do
+ test "defaults with type that implements `type_cast_for_database`" do
type = Class.new(ActiveRecord::Type::Value) do
def type_cast(value)
value.to_i
end
- def type_cast_for_write(value)
+ def type_cast_for_database(value)
value.to_s
end
-
- alias type_cast_for_database type_cast_for_write
end
model_class = Class.new(ActiveRecord::Base) do
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index c0440744e9..bd77c412f6 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -33,6 +33,17 @@ class FinderTest < ActiveRecord::TestCase
assert_equal(topics(:first).title, Topic.find(1).title)
end
+ def test_find_with_proc_parameter_and_block
+ exception = assert_raises(RuntimeError) do
+ Topic.all.find(-> { raise "should happen" }) { |e| e.title == "non-existing-title" }
+ end
+ assert_equal "should happen", exception.message
+
+ assert_nothing_raised(RuntimeError) do
+ Topic.all.find(-> { raise "should not happen" }) { |e| e.title == topics(:first).title }
+ end
+ end
+
def test_find_passing_active_record_object_is_deprecated
assert_deprecated do
Topic.find(Topic.last)
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 8bbc0af758..042fdaf0bb 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -84,12 +84,6 @@ class FixturesTest < ActiveRecord::TestCase
assert fixtures.detect { |f| f.name == 'collections' }, "no fixtures named 'collections' in #{fixtures.map(&:name).inspect}"
end
- def test_create_symbol_fixtures_is_deprecated
- assert_deprecated do
- ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :collections, :collections => 'Course') { Course.connection }
- end
- end
-
def test_attributes
topics = create_fixtures("topics").first
assert_equal("The First Topic", topics["first"]["title"])
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 93fd3b9605..c221430757 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -272,10 +272,6 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert p.treasures.empty?
assert RichPerson.connection.select_all("SELECT * FROM peoples_treasures WHERE rich_person_id = 1").empty?
end
-
- def test_quoted_locking_column_is_deprecated
- assert_deprecated { ActiveRecord::Base.quoted_locking_column }
- end
end
class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 793e193329..c6e73f78cc 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -95,8 +95,8 @@ class ReflectionTest < ActiveRecord::TestCase
column = @first.column_for_attribute("attribute_that_doesnt_exist")
object = Object.new
- assert_equal object, column.type_cast(object)
- assert_equal object, column.type_cast_for_write(object)
+ assert_equal object, column.type_cast_from_database(object)
+ assert_equal object, column.type_cast_from_user(object)
assert_equal object, column.type_cast_for_database(object)
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index e2a18d138d..5f02d39e32 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -394,7 +394,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
output = standard_dump
assert_no_match %r{create_table "foo_.+_bar"}, output
- assert_no_match %r{create_index "foo_.+_bar"}, output
+ assert_no_match %r{add_index "foo_.+_bar"}, output
assert_no_match %r{create_table "schema_migrations"}, output
ensure
migration.migrate(:down)
diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb
index 77ab427be0..0472246f71 100644
--- a/activerecord/test/cases/timestamp_test.rb
+++ b/activerecord/test/cases/timestamp_test.rb
@@ -71,24 +71,6 @@ class TimestampTest < ActiveRecord::TestCase
assert_equal @previously_updated_at, @developer.updated_at
end
- def test_saving_when_callback_sets_record_timestamps_to_false_doesnt_update_its_timestamp
- klass = Class.new(Developer) do
- before_update :cancel_record_timestamps
- def cancel_record_timestamps
- self.record_timestamps = false
- return true
- end
- end
-
- developer = klass.first
- previously_updated_at = developer.updated_at
-
- developer.name = "New Name"
- developer.save!
-
- assert_equal previously_updated_at, developer.updated_at
- end
-
def test_touching_an_attribute_updates_timestamp
previously_created_at = @developer.created_at
@developer.touch(:created_at)
@@ -399,6 +381,19 @@ class TimestampTest < ActiveRecord::TestCase
assert_not_equal time, pet.updated_at
end
+ def test_timestamp_column_values_are_present_in_the_callbacks
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = 'people'
+
+ before_create do
+ self.born_at = self.created_at
+ end
+ end
+
+ person = klass.create first_name: 'David'
+ assert_not_equal person.born_at, nil
+ end
+
def test_timestamp_attributes_for_create
toy = Toy.first
assert_equal [:created_at, :created_on], toy.send(:timestamp_attributes_for_create)
diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb
index 5d5f442d3a..731f8cfba3 100644
--- a/activerecord/test/cases/types_test.rb
+++ b/activerecord/test/cases/types_test.rb
@@ -6,141 +6,141 @@ module ActiveRecord
class TypesTest < ActiveRecord::TestCase
def test_type_cast_boolean
type = Type::Boolean.new
- assert type.type_cast('').nil?
- assert type.type_cast(nil).nil?
-
- assert type.type_cast(true)
- assert type.type_cast(1)
- assert type.type_cast('1')
- assert type.type_cast('t')
- assert type.type_cast('T')
- assert type.type_cast('true')
- assert type.type_cast('TRUE')
- assert type.type_cast('on')
- assert type.type_cast('ON')
+ assert type.type_cast_from_user('').nil?
+ assert type.type_cast_from_user(nil).nil?
+
+ assert type.type_cast_from_user(true)
+ assert type.type_cast_from_user(1)
+ assert type.type_cast_from_user('1')
+ assert type.type_cast_from_user('t')
+ assert type.type_cast_from_user('T')
+ assert type.type_cast_from_user('true')
+ assert type.type_cast_from_user('TRUE')
+ assert type.type_cast_from_user('on')
+ assert type.type_cast_from_user('ON')
# explicitly check for false vs nil
- assert_equal false, type.type_cast(false)
- assert_equal false, type.type_cast(0)
- assert_equal false, type.type_cast('0')
- assert_equal false, type.type_cast('f')
- assert_equal false, type.type_cast('F')
- assert_equal false, type.type_cast('false')
- assert_equal false, type.type_cast('FALSE')
- assert_equal false, type.type_cast('off')
- assert_equal false, type.type_cast('OFF')
- assert_equal false, type.type_cast(' ')
- assert_equal false, type.type_cast("\u3000\r\n")
- assert_equal false, type.type_cast("\u0000")
- assert_equal false, type.type_cast('SOMETHING RANDOM')
+ assert_equal false, type.type_cast_from_user(false)
+ assert_equal false, type.type_cast_from_user(0)
+ assert_equal false, type.type_cast_from_user('0')
+ assert_equal false, type.type_cast_from_user('f')
+ assert_equal false, type.type_cast_from_user('F')
+ assert_equal false, type.type_cast_from_user('false')
+ assert_equal false, type.type_cast_from_user('FALSE')
+ assert_equal false, type.type_cast_from_user('off')
+ assert_equal false, type.type_cast_from_user('OFF')
+ assert_equal false, type.type_cast_from_user(' ')
+ assert_equal false, type.type_cast_from_user("\u3000\r\n")
+ assert_equal false, type.type_cast_from_user("\u0000")
+ assert_equal false, type.type_cast_from_user('SOMETHING RANDOM')
end
def test_type_cast_string
type = Type::String.new
- assert_equal "1", type.type_cast(true)
- assert_equal "0", type.type_cast(false)
- assert_equal "123", type.type_cast(123)
+ assert_equal "1", type.type_cast_from_user(true)
+ assert_equal "0", type.type_cast_from_user(false)
+ assert_equal "123", type.type_cast_from_user(123)
end
def test_type_cast_integer
type = Type::Integer.new
- assert_equal 1, type.type_cast(1)
- assert_equal 1, type.type_cast('1')
- assert_equal 1, type.type_cast('1ignore')
- assert_equal 0, type.type_cast('bad1')
- assert_equal 0, type.type_cast('bad')
- assert_equal 1, type.type_cast(1.7)
- assert_equal 0, type.type_cast(false)
- assert_equal 1, type.type_cast(true)
- assert_nil type.type_cast(nil)
+ assert_equal 1, type.type_cast_from_user(1)
+ assert_equal 1, type.type_cast_from_user('1')
+ assert_equal 1, type.type_cast_from_user('1ignore')
+ assert_equal 0, type.type_cast_from_user('bad1')
+ assert_equal 0, type.type_cast_from_user('bad')
+ assert_equal 1, type.type_cast_from_user(1.7)
+ assert_equal 0, type.type_cast_from_user(false)
+ assert_equal 1, type.type_cast_from_user(true)
+ assert_nil type.type_cast_from_user(nil)
end
def test_type_cast_non_integer_to_integer
type = Type::Integer.new
- assert_nil type.type_cast([1,2])
- assert_nil type.type_cast({1 => 2})
- assert_nil type.type_cast((1..2))
+ assert_nil type.type_cast_from_user([1,2])
+ assert_nil type.type_cast_from_user({1 => 2})
+ assert_nil type.type_cast_from_user((1..2))
end
def test_type_cast_activerecord_to_integer
type = Type::Integer.new
firm = Firm.create(:name => 'Apple')
- assert_nil type.type_cast(firm)
+ assert_nil type.type_cast_from_user(firm)
end
def test_type_cast_object_without_to_i_to_integer
type = Type::Integer.new
- assert_nil type.type_cast(Object.new)
+ assert_nil type.type_cast_from_user(Object.new)
end
def test_type_cast_nan_and_infinity_to_integer
type = Type::Integer.new
- assert_nil type.type_cast(Float::NAN)
- assert_nil type.type_cast(1.0/0.0)
+ assert_nil type.type_cast_from_user(Float::NAN)
+ assert_nil type.type_cast_from_user(1.0/0.0)
end
def test_type_cast_float
type = Type::Float.new
- assert_equal 1.0, type.type_cast("1")
+ assert_equal 1.0, type.type_cast_from_user("1")
end
def test_type_cast_decimal
type = Type::Decimal.new
- assert_equal BigDecimal.new("0"), type.type_cast(BigDecimal.new("0"))
- assert_equal BigDecimal.new("123"), type.type_cast(123.0)
- assert_equal BigDecimal.new("1"), type.type_cast(:"1")
+ assert_equal BigDecimal.new("0"), type.type_cast_from_user(BigDecimal.new("0"))
+ assert_equal BigDecimal.new("123"), type.type_cast_from_user(123.0)
+ assert_equal BigDecimal.new("1"), type.type_cast_from_user(:"1")
end
def test_type_cast_binary
type = Type::Binary.new
- assert_equal nil, type.type_cast(nil)
- assert_equal "1", type.type_cast("1")
- assert_equal 1, type.type_cast(1)
+ assert_equal nil, type.type_cast_from_user(nil)
+ assert_equal "1", type.type_cast_from_user("1")
+ assert_equal 1, type.type_cast_from_user(1)
end
def test_type_cast_time
type = Type::Time.new
- assert_equal nil, type.type_cast(nil)
- assert_equal nil, type.type_cast('')
- assert_equal nil, type.type_cast('ABC')
+ assert_equal nil, type.type_cast_from_user(nil)
+ assert_equal nil, type.type_cast_from_user('')
+ assert_equal nil, type.type_cast_from_user('ABC')
time_string = Time.now.utc.strftime("%T")
- assert_equal time_string, type.type_cast(time_string).strftime("%T")
+ assert_equal time_string, type.type_cast_from_user(time_string).strftime("%T")
end
def test_type_cast_datetime_and_timestamp
type = Type::DateTime.new
- assert_equal nil, type.type_cast(nil)
- assert_equal nil, type.type_cast('')
- assert_equal nil, type.type_cast(' ')
- assert_equal nil, type.type_cast('ABC')
+ assert_equal nil, type.type_cast_from_user(nil)
+ assert_equal nil, type.type_cast_from_user('')
+ assert_equal nil, type.type_cast_from_user(' ')
+ assert_equal nil, type.type_cast_from_user('ABC')
datetime_string = Time.now.utc.strftime("%FT%T")
- assert_equal datetime_string, type.type_cast(datetime_string).strftime("%FT%T")
+ assert_equal datetime_string, type.type_cast_from_user(datetime_string).strftime("%FT%T")
end
def test_type_cast_date
type = Type::Date.new
- assert_equal nil, type.type_cast(nil)
- assert_equal nil, type.type_cast('')
- assert_equal nil, type.type_cast(' ')
- assert_equal nil, type.type_cast('ABC')
+ assert_equal nil, type.type_cast_from_user(nil)
+ assert_equal nil, type.type_cast_from_user('')
+ assert_equal nil, type.type_cast_from_user(' ')
+ assert_equal nil, type.type_cast_from_user('ABC')
date_string = Time.now.utc.strftime("%F")
- assert_equal date_string, type.type_cast(date_string).strftime("%F")
+ assert_equal date_string, type.type_cast_from_user(date_string).strftime("%F")
end
def test_type_cast_duration_to_integer
type = Type::Integer.new
- assert_equal 1800, type.type_cast(30.minutes)
- assert_equal 7200, type.type_cast(2.hours)
+ assert_equal 1800, type.type_cast_from_user(30.minutes)
+ assert_equal 7200, type.type_cast_from_user(2.hours)
end
def test_string_to_time_with_timezone
[:utc, :local].each do |zone|
with_timezone_config default: zone do
type = Type::DateTime.new
- assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast("Wed, 04 Sep 2013 03:00:00 EAT")
+ assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast_from_user("Wed, 04 Sep 2013 03:00:00 EAT")
end
end
end
@@ -149,7 +149,7 @@ module ActiveRecord
def test_binary_encoding
type = SQLite3Binary.new
utf8_string = "a string".encode(Encoding::UTF_8)
- type_cast = type.type_cast(utf8_string)
+ type_cast = type.type_cast_from_user(utf8_string)
assert_equal Encoding::ASCII_8BIT, type_cast.encoding
end
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
index d4f8ef5b4d..9f1d110ddb 100644
--- a/activerecord/test/cases/yaml_serialization_test.rb
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -1,8 +1,10 @@
require 'cases/helper'
require 'models/topic'
+require 'models/post'
+require 'models/author'
class YamlSerializationTest < ActiveRecord::TestCase
- fixtures :topics
+ fixtures :topics, :authors, :posts
def test_to_yaml_with_time_with_zone_should_not_raise_exception
with_timezone_config aware_attributes: true, zone: "Pacific Time (US & Canada)" do
@@ -69,4 +71,15 @@ class YamlSerializationTest < ActiveRecord::TestCase
assert_not topic.new_record?, "Loaded records without ID are not new"
assert_not YAML.load(YAML.dump(topic)).new_record?, "Record should not be new after deserialization"
end
+
+ def test_types_of_virtual_columns_are_not_changed_on_round_trip
+ author = Author.select('authors.*, count(posts.id) as posts_count')
+ .joins(:posts)
+ .group('authors.id')
+ .first
+ dumped = YAML.load(YAML.dump(author))
+
+ assert_equal 5, author.posts_count
+ assert_equal 5, dumped.posts_count
+ end
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 5f459cf682..98fd0b6803 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -529,6 +529,7 @@ ActiveRecord::Schema.define do
t.references :best_friend
t.references :best_friend_of
t.integer :insures, null: false, default: 0
+ t.timestamp :born_at
t.timestamps
end