Class: ActiveJsonModel::ActiveRecordType

Inherits:
ActiveRecord::Type::Value
  • Object
show all
Includes:
ActiveModel::Type::Helpers::Mutable
Defined in:
lib/active_json_model/active_record_type.rb

Overview

Allows instances of ActiveJsonModels to be serialized JSONB columns for ActiveRecord models.

class Credentials < ::ActiveJsonModel
  def self.attribute_type
    ActiveRecordType.new(Credentials)
  end
end

class User < ActiveRecord::Base
  attribute :credentials, Credentials.attribute_type
end

Alternatively, the type can be registered ahead of time:

# config/initializers/types.rb
ActiveRecord::Type.register(:credentials_type, Credentials.attribute_type)

Then the custom type can be used as:

class User < ActiveRecord::Base
  attribute :credentials, :credentials_type
end

This is based on: jetrockets.pro/blog/rails-5-attributes-api-value-objects-and-jsonb

Direct Known Subclasses

ActiveRecordEncryptedType

Instance Method Summary collapse

Constructor Details

#initialize(clazz) ⇒ ActiveRecordType

Create an instance bound to a ActiveJsonModel class.

e.g.

class Credentials < ::ActiveJsonModel; end
#...
return ActiveRecordType.new(Credentials)


44
45
46
# File 'lib/active_json_model/active_record_type.rb', line 44

def initialize(clazz)
  @clazz = clazz
end

Instance Method Details

#cast(value) ⇒ Object



52
53
54
# File 'lib/active_json_model/active_record_type.rb', line 52

def cast(value)
  @clazz.active_json_model_cast(value)
end

#changed_in_place?(raw_old_value, new_value) ⇒ Boolean

Override to handle issues comparing hashes encoded as strings, where the actual order doesn’t matter.

Returns:

  • (Boolean)


76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/active_json_model/active_record_type.rb', line 76

def changed_in_place?(raw_old_value, new_value)
  if raw_old_value.nil? || new_value.nil?
    raw_old_value == new_value
  else
    # Decode is necessary because postgres can change the order of hashes. Round-tripping on the new value side
    # is to handle any dates that might be rendered as strings.
    decoded_raw = ::ActiveSupport::JSON.decode(raw_old_value)
    round_tripped_new = ::ActiveSupport::JSON.decode(new_value.class.dump(new_value))

    decoded_raw != round_tripped_new
  end
end

#deserialize(value) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/active_json_model/active_record_type.rb', line 56

def deserialize(value)
  if String === value
    decoded = ::ActiveSupport::JSON.decode(value) rescue nil
    @clazz.load(decoded)
  else
    super
  end
end

#serialize(value) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/active_json_model/active_record_type.rb', line 65

def serialize(value)
  if value.respond_to?(:dump_to_json)
    ::ActiveSupport::JSON.encode(value.dump_to_json)
  elsif ::Hash === value ||  ::HashWithIndifferentAccess === value || ::Array === value
    ::ActiveSupport::JSON.encode(value)
  else
    super
  end
end

#typeObject



48
49
50
# File 'lib/active_json_model/active_record_type.rb', line 48

def type
  :jsonb
end