We had the table configurations
with column preferences
of type jsbon
and default {}
.
Initial migration:
def up
add_column :configurations, :preferences, :jsonb
change_column_default :configurations, :preferences, "{}"
end
def down
remove_column :configurations, :preferences
end
We later decided to change this column's datatype to text
, array: true
and default: []
.
Because this table had no entries in our production servers, we dropped the column, created it again with a different datatype and added the new default value, all in the same migration:
Second migration:
def up
safety_assured {
remove_column :configurations, :preferences
add_column :configurations, :preferences, :text, array: true
change_column_default :configurations, :preferences, []
}
end
def down
safety_assured {
remove_column :configurations, :preferences
add_column :configurations, :preferences, :jsonb
change_column_default :configurations, :preferences, "{}"
}
end
schema.rb after migration:
t.text "preferences", default: [], array: true
Now, when we create a new entry on the configurations
table using the web interface and going through the controller, preferences
is populated with the old {}
default value.
Controller action:
def create
@configurations = association.build_configuration
end
To make things even more strange, using the server console
to build the record instead, ActiveRecord uses the right default []
:
Console:
Association.build_configuration
=> #<Configuration id: nil, association_id: 1, created_at: nil, updated_at: nil, preferences: []>
Why is the ActiveRecord build
method using different defaults when used in the controller vs using it via console?
Things we've tried:
- Restarting the server after deploy
- Running
Configuration.connection.schema_cache.clear!
- Running
Configuration.reset_column_information
EDIT:
This is what Configuration._default_attributes
returns:
"preferences"=>
#<ActiveModel::Attribute::FromDatabase:0x000055988ccd99f0
@name="preferences",
@original_attribute=nil,
@type=
#<ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array:0x000055988cce8d38
@delimiter=",",
@pg_decoder=#<PG::TextDecoder::Array:0x000055988cce89f0 "text[]" elements_type=nil needs quotation>,
@pg_encoder=#<PG::TextEncoder::Array:0x000055988cce8bd0 "text[]" elements_type=nil needs quotation>,
@subtype=#<ActiveRecord::Type::Text:0x000055988cdef380 @limit=nil, @precision=nil, @scale=nil>>,
@value_before_type_cast="{}">
CodePudding user response:
Solution:
Arrays in Postgres use curly braces, which is why it's showing up that way. Active Record is deserializing it to a Ruby array in the example above.