Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions activemodel/lib/active_model/type/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def serialize(value)
end

def deserialize(value)
return nil if value.nil?

serializer.decode(value).map { |el| @type_object.deserialize(el) }
end

Expand All @@ -66,6 +68,8 @@ def changed_in_place?(raw_old_value, new_value)
end

def valid_value?(value)
return true if value.nil?

value.is_a?(Array) && value.all? { |el| @type_object.valid_value?(el) }
end

Expand Down
2 changes: 2 additions & 0 deletions activerecord/lib/active_record/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def current_adapter_name
BigInteger = ActiveModel::Type::BigInteger
Binary = ActiveModel::Type::Binary
Boolean = ActiveModel::Type::Boolean
Collection = ActiveModel::Type::Collection
Decimal = ActiveModel::Type::Decimal
Float = ActiveModel::Type::Float
Integer = ActiveModel::Type::Integer
Expand All @@ -69,6 +70,7 @@ def current_adapter_name
register(:big_integer, Type::BigInteger, override: false)
register(:binary, Type::Binary, override: false)
register(:boolean, Type::Boolean, override: false)
register(:collection, Type::Collection, override: false)
register(:date, Type::Date, override: false)
register(:datetime, Type::DateTime, override: false)
register(:decimal, Type::Decimal, override: false)
Expand Down
54 changes: 54 additions & 0 deletions activerecord/test/cases/collection_attribute_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

require "cases/helper"

class CollectionAttributeTest < ActiveRecord::TestCase
self.use_transactional_tests = false

class CollectionDataTypeOnText < ActiveRecord::Base
attribute :integers, :collection, element_type: :integer
end

class CollectionDataTypeOnJson < ActiveRecord::Base
attribute :integers, :collection, element_type: :integer
end

setup do
@connection = ActiveRecord::Base.lease_connection
@connection.create_table(CollectionDataTypeOnText.table_name, force: true) { |t| t.text :integers }
@connection.create_table(CollectionDataTypeOnJson.table_name, force: true) { |t| t.json :integers }
end

teardown do
@connection.drop_table CollectionDataTypeOnText.table_name, if_exists: true
@connection.drop_table CollectionDataTypeOnJson.table_name, if_exists: true
CollectionDataTypeOnText.reset_column_information
CollectionDataTypeOnJson.reset_column_information
end

test "writes :collection attribute instance to text column" do
integers = ["1", "2", "3"]
record = CollectionDataTypeOnText.create!(integers: integers)

assert_equal integers.map(&:to_i), record.integers
end

test "writes :collection attribute instance to json column" do
integers = ["1", "2", "3"]
record = CollectionDataTypeOnJson.create!(integers: integers)

assert_equal integers.map(&:to_i), record.integers
end

test "reads nil :collection attribute instance from text column" do
record = CollectionDataTypeOnText.create!(integers: nil)

assert_empty record.integers
end

test "reads nil :collection attribute instance from json column" do
record = CollectionDataTypeOnJson.create!(integers: nil)

assert_empty record.integers
end
end