Class: AttrJson::Type::Model

Inherits:
ActiveModel::Type::Value
  • Object
show all
Defined in:
lib/attr_json/type/model.rb

Overview

An ActiveModel::Type representing a particular AttrJson::Model class, supporting casting, serialization, and deserialization from/to JSON-able serializable hashes.

You create one with AttrJson::Model::Type.new(attr_json_model_class), but normally that's only done in AttrJson::Model.to_type, there isn't an anticipated need to create from any other place.

Defined Under Namespace

Classes: BadCast

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, strip_nils: :safely) ⇒ Model

Returns a new instance of Model.

Parameters:

  • model (AttrJson::Model)

    the model class object

  • strip_nils (Symbol, Boolean) (defaults to: :safely)

    true, false, or :safely, As a type, should we strip nils when serialiing? This value passed to AttrJson::Model#serialized_hash(strip_nils). by default it's :safely, we strip nils when it can be done safely to preserve default overrides.



25
26
27
28
29
# File 'lib/attr_json/type/model.rb', line 25

def initialize(model, strip_nils: :safely)
  #TODO type check, it really better be a AttrJson::Model. maybe?
  @model = model
  @strip_nils = strip_nils
end

Instance Attribute Details

#modelObject

Returns the value of attribute model.



17
18
19
# File 'lib/attr_json/type/model.rb', line 17

def model
  @model
end

#strip_nilsObject

Returns the value of attribute strip_nils.



17
18
19
# File 'lib/attr_json/type/model.rb', line 17

def strip_nils
  @strip_nils
end

Instance Method Details

#cast(v) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/attr_json/type/model.rb', line 35

def cast(v)
  if v.nil?
    # important to stay nil instead of empty object, because they
    # are different things.
    v
  elsif v.kind_of? model
    v
  elsif v.respond_to?(:to_hash)
    # to_hash is actually the 'implicit' conversion, it really is a hash
    # even though it isn't is_a?(Hash), try to_hash first before to_h,
    # the explicit conversion.
    model.new(v.to_hash)
  elsif v.respond_to?(:to_h)
    # TODO Maybe we ought not to do this on #to_h?
    model.new(v.to_h)
  elsif model.attr_json_config.bad_cast == :as_nil
    # This was originally default behavior, to be like existing ActiveRecord
    # which kind of silently does this for non-castable basic values. That
    # ended up being confusing in the basic case, so now we raise by default,
    # but this is still configurable.
    nil
  else
    raise BadCast.new("Can not cast from #{v.inspect} to #{self.type}")
  end
end

#changed_in_place?(raw_old_value, new_value) ⇒ Boolean

these guys are definitely mutable, so we need this.

Returns:

  • (Boolean)


100
101
102
# File 'lib/attr_json/type/model.rb', line 100

def changed_in_place?(raw_old_value, new_value)
  serialize(new_value) != raw_old_value
end

#deserialize(v) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/attr_json/type/model.rb', line 71

def deserialize(v)
  if v.nil?
    # important to stay nil instead of empty object, because they
    # are different things.
    v
  elsif v.kind_of? model
    v
  elsif v.respond_to?(:to_hash)
    # to_hash is actually the 'implicit' conversion, it really is a hash
    # even though it isn't is_a?(Hash), try to_hash first before to_h,
    # the explicit conversion.
    model.new_from_serializable(v.to_hash)
  elsif v.respond_to?(:to_h)
    # TODO Maybe we ought not to do this on #to_h? especially here in deserialize?
    model.new_from_serializable(v.to_h)
  elsif model.attr_json_config.bad_cast == :as_nil
    # TODO should we have different config value for bad_deserialize vs bad_cast?

    # This was originally default behavior, to be like existing ActiveRecord
    # which kind of silently does this for non-castable basic values. That
    # ended up being confusing in the basic case, so now we raise by default,
    # but this is still configurable.
    nil
  else
    raise BadCast.new("Can not cast from #{v.inspect} to #{self.type}")
  end
end

#serialize(v) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/attr_json/type/model.rb', line 61

def serialize(v)
  if v.nil?
    nil
  elsif v.kind_of?(model)
    v.serializable_hash(strip_nils: strip_nils)
  else
    (cast_v = cast(v)) && cast_v.serializable_hash(strip_nils: strip_nils)
  end
end

#typeObject



31
32
33
# File 'lib/attr_json/type/model.rb', line 31

def type
  model.to_param.underscore.to_sym
end

#value_for_contains_query(key_path_arr, value) ⇒ Object

This is used only by our own keypath-chaining query stuff.



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/attr_json/type/model.rb', line 105

def value_for_contains_query(key_path_arr, value)
  first_key, rest_keys = key_path_arr.first, key_path_arr[1..-1]
  attr_def = model.attr_json_registry.fetch(first_key)
  {
    attr_def.store_key => if rest_keys.present?
      attr_def.type.value_for_contains_query(rest_keys, value)
    else
      attr_def.serialize(attr_def.cast value)
    end
  }
end