How to serialize hstore for Rails model


#1

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?


#2

@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?


#3

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!


#4

I believe constructor_type :symbolized should work in your case.


#5

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.


#6

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.