How to serialize hstore for Rails model

I have been using Virtus, and in the documentation of this project it says this gem dry-types can be a replacement of the Virtus gem, I’m using it to serialize/parse my hstore column in this way: https://nandovieira.com/using-postgresql-and-hstore-with-rails (Using the Virtus gem)

Today I have tried to replace the Virtus implementation with the dry-types gem without success, could you please write an example of how to accomplish this with dry-types?

@victorhazbun Can you share with us what you tried (code examples are great), and how it specifically fell short of what you wanted to achieve?

I’ll continue this thread because I’m trying to do the same thing.

Say I have a user model with a hstore column:

class User < ApplicationRecord
  serialize :meta, Options
end

With a Meta virtus class that looks like:

class Meta
  include Virtus.model

  attribute :badge_number, Integer    
  attribute :reminders_enabled, Boolean, default: false
  attribute :nickname, String

  def self.dump(meta)
    meta.to_hash
  end

  def self.load(meta
    new(meta)
  end
end

If the hstore content of meta is "nickname"=>"awesome", "badge_number"=>"12", "reminders_enabled"=>"true", virtus will properly coerce the values in the Preferences::User class and I can do things such as user.meta.badge_number = 1; user.save and Rails/virtus does all of the right things and updates the backing hstore column.

How do I implement such functionality with dry types?

I’ve tried

module Types
  include Dry::Types.module
end

class Meta < Dry::Struct
  constructor_type :schema

  attribute :badge_number, Types::Int
  attribute :reminders_enabled, Types::Bool
  attribute :nickname, String

  def self.dump(meta)
    meta.to_hash
  end

  def self.load(meta)
    new(meta)
  end
end

but all of the attributes in meta are then nil.

If I try with the permissive constructor type, I get Dry::Struct::Error ([Meta.new] :badge_number is missing in Hash input).

I use this pattern of a hstore meta or options or some column, serialized with Virtus all over my app, it’s been super useful. I feel like I’m missing something obvious here, so would appreciate any help you all can offer.

Thanks!

I believe constructor_type :symbolized should work in your case.

When attempting to use constructor_type :symbolized, I get the error:

.../.bundle/gems/dry-core-0.4.5/lib/dry/core/class_attributes.rb:65:in `block (3 levels) in defines': 
Value :symbolized is invalid for class attribute :constructor_type (Dry::Core::InvalidClassAttributeValue)

This is with dry-struct 0.4.0 and dry-types 0.12.2.

It seems like that they aren’t supported anymore? https://github.com/dry-rb/dry-struct/commit/0bc4fed0394b3e5009a98efb99b07321abb4e508. I see a note in that commit on using dry-validation, but the note was removed in the commit so not sure what the recommended strategy is here.

Sorry to bring up the old thread - but I’d still love to know if anyone has any suggestions on storing dry-types in Rails jsonb columns. Did some searching/googling and didn’t see anything. Still on virtus and would love to switch over!

You can achieve this by defining a struct that will symbolize its keys. See dry-struct recipes for more details.

After try a lot of things, I ended up using GitHub - cgriego/active_attr: What ActiveModel left out my old virtus hstore and serialization worked as expected