Closed stex closed 11 months ago
hey,
it's possible, but since it's very domain specific you have to do some plumbing by hand. Here's an example how could you handle it:
require 'shale'
class Person
attr_accessor :id
attr_accessor :pet
end
class Dog
attr_accessor :dog_name
end
class Cat
attr_accessor :cat_name
end
# Mapper
class PersonMapper < Shale::Mapper
model Person
attribute :id, Shale::Type::Integer
json do
map 'id', to: :id
map 'pet', using: { to: :pet_to_json, from: :pet_from_json }
end
def pet_from_json(model, value)
case value['type']
when 'Dog'
model.pet = Dog.new
model.pet.dog_name = value['dog_name']
# or mayby load it from database
# model.pet = Dog.find_by(name: value['dog_name'])
when 'Cat'
model.pet = Cat.new
model.pet.cat_name = value['cat_name']
end
end
def pet_to_json(model, doc)
case model.pet
when Dog
doc['pet'] = { type: 'Dog', **DogMapper.as_json(model.pet) }
when Cat
doc['pet'] = { type: 'Cat', **CatMapper.as_json(model.pet) }
end
end
end
class DogMapper < Shale::Mapper
model Dog
attribute :dog_name, Shale::Type::String
end
class CatMapper < Shale::Mapper
model Cat
attribute :cat_name, Shale::Type::String
end
person = Person.new
person.id = 1
person.pet = Dog.new
person.pet.dog_name = 'Lucky'
puts PersonMapper.to_json(person)
person = Person.new
person.id = 1
person.pet = Cat.new
person.pet.cat_name = 'Fluffy'
puts PersonMapper.to_json(person)
puts '--------------------'
p PersonMapper.from_json('{"id":1,"pet":{"type":"Dog","dog_name":"Lucky"}}')
p PersonMapper.from_json('{"id":1,"pet":{"type":"Cat","cat_name":"Fluffy"}}')
I see, thank you very much for your detailed explanation! ❤️
I was hoping there was a way without having to manually define the association, but that's definitely a way.
Hey!
First of all, thanks a lot for this gem, having a serializer and deserializer for JSON, YAML and XML at the same time is absolutely wonderful!
I came across an issue that currently hinders its usefulness for me though. Maybe it's such a special case that it's not worth investigating or maybe there is already a solution that I simply didn't see.
In my case, the issue arose when using Rails models as custom models:
As you can see, I didn't find a way to describe the polymorphic type for
pet
. How I would handle this if I'd (de)serialize it by hand:Serialize (JSON as example)
Take the actual type of the object to be serialized and add it as
type
field.Deserialize
Expect a
type
field and use the corresponding mapper.Is this something that's simply not possible or did I miss it? As far as I can see it, I can manipulate the values when (de)serializing, but not the type.
Thanks a lot in advance!