Perhaps my understanding of how this is supposed to work is wrong, but I seeing strings stored in my DB when I would expect them to be a jsonb array. Here is how I have things setup:
Migration
t.jsonb :variables, array: true
Model
attribute :variables, :variable, array: true
Custom ActiveRecord::Type
ActiveRecord::Type.register(:variable, Variable::Type)
Custom Variable Type
class Variable::Type < ActiveRecord::Type::Json
include ActiveModel::Type::Helpers::Mutable
# Type casts a value from user input (e.g. from a setter). This value may be a string from the form builder, or a ruby object passed to a setter. There is currently no way to differentiate between which source it came from.
# - value: The raw input, as provided to the attribute setter.
def cast(value)
unless value.nil?
value = Variable.new(value) if !value.kind_of?(Variable)
value
end
end
# Converts a value from database input to the appropriate ruby type. The return value of this method will be returned from ActiveRecord::AttributeMethods::Read#read_attribute. The default implementation just calls #cast.
# - value: The raw input, as provided from the database.
def deserialize(value)
unless value.nil?
value = super if value.kind_of?(String)
value = Variable.new(value) if value.kind_of?(Hash)
value
end
end
So this method does work from the application's perspective. I can set the value as variables = [Variable.new, Variable.new] and it correctly stores in the DB, and retrieves back as an array of [Variable, Variable].
What concerns me, and the root of this question, is that in the database, the variable is stored using double escaped strings rather than json objects:
{
"{\"token\": \"a\", \"value\": 1, \"default_value\": 1}",
"{\"token\": \"b\", \"value\": 2, \"default_value\": 2}"
}
I would expect them to be stored something more resembling a json object like this:
{
{"token": "a", "value": 1, "default_value": 1},
{"token": "b", "value": 2, "default_value": 2}
}
The reason for this is that, from my understanding, future querying on this column directly from the DB will be faster/easier if in a json format, rather than a string format. Querying through rails would remain unaffected.
How can I get my Postgres DB to store the array of jsonb properly through rails?
attribute :variables, :variable, array: trueis most likely the culprit here is and is completely superfluous.array: truein the migration does nothing. Postgres will still take any scalar type (string, integer, array, object). Its used when declaring native array columns ast.string :variables, array: true. You also seem to be confusing arrays with objects (json) / hashes (ruby).