DmitryTsepelev / store_model

Work with JSON-backed attributes as ActiveRecord-ish models
MIT License
1.04k stars 85 forks source link

Decoding Custom Types #133

Open barnaclebarnes opened 1 year ago

barnaclebarnes commented 1 year ago

I have the following:

# app/models/attributes/content_versions.rb
class Attributes::ContentVersions
  include StoreModel::Model

  attribute :html, Base64Type.new
  attribute :xlsx, Base64Type.new
end
# app/types/base64_type.rb

class Base64Type < ActiveRecord::Type::Value
  def type
    :base64_string
  end

  def cast(value)
    return if value.blank?

    Base64.encode64(value)
  end
end
it "should return a summary of the content" do
      project = create(:project)
      project.content_summary.html = "<html></html>"
      expect(project.content_summary.html).to eq("<html></html>")
    end

Which gets:

       - <html></html>
       + PGh0bWw+PC9odG1sPg==\n

It seems that I can encode the values to the fields but cannot decode the values. I tried putting this in the base64_type.rb but that didn't seem to get called.

  def deserialize(value)
    return if value.blank?

    Base64.decode64(value)
  end

How do we override the deserialiser?

DmitryTsepelev commented 1 year ago

Hi @barnaclebarnes! Sorry it took me too long to respond 😞 The problem is that Rails (it's a Rails code, gem has nothing to do with it) uses cast/cast_value for both encoding and decoding so we have to do something like this:

class Base64Type < ActiveRecord::Type::Value
    def type
      :base64_string
    end

    def cast(value)
      return if value.blank?

      if base64?(value)
        Base64.decode64(value)
      else
        Base64.encode64(value)
      end
    end

    private

    def base64?(value)
      value.is_a?(String) && Base64.encode64(Base64.decode64(value)) == value
    end
  end

We do the same dirty hack in One implementation