trailblazer / representable

Maps representation documents from and to Ruby objects. Includes JSON, XML and YAML support, plain properties and compositions.
http://trailblazer.to/2.1/docs/representable.html
MIT License
689 stars 108 forks source link

No way to error on unknown properties #220

Open imoverclocked opened 7 years ago

imoverclocked commented 7 years ago

Given a class:

class SongRepresenter < Representable::Decorator
  include Representable::JSON

  property :title
  property :track
end

and some data to instantiate it with:

{"title": "Foggy Mountain Breakdown", "track": 2, "genre": "bluegrass"}

There is no way to discover that genre is about to be harshly ignored or dropped on the ground. Another similar problem with slightly different data:

{"title": "Foggy Mountain Breakdown", "trach": 2}

since trach != track, our optional attribute is also silently dropped without warning.

imoverclocked commented 7 years ago
[4] pry(main)> class Song
[4] pry(main)*   attr_accessor :title
[4] pry(main)*   attr_accessor :track
[4] pry(main)*   attr_accessor :foo
[4] pry(main)* end
=> nil
[5] pry(main)> puts SongRepresenter.new(Song.new()).from_json(%{ {"title":"Roxanne", "foo": "bar", "baz": "quux"} }).to_json
{"title":"Roxanne"}
=> nil
apotonick commented 7 years ago

Yes, that's per design! Representable is a document mapper and not a form object.

We're actually thinking about allowing the detection of that, since it will also be very helpful in Reform.

apotonick commented 7 years ago

The problem is that this might appear very simple with hashes (as in, find all keys in the incoming doc, compare to what we have), however, with XML documents as an example, this gets much trickier. I am wondering if that should probably be some Reform-specific feature, instead. :thinking:

imoverclocked commented 7 years ago

Yeah, I was browsing through the source to see if there would be any quick+clean way to patch this in but nothing popped out at me. The current design feels pretty heavy towards not having this feature.

Some extremely pragmatic part of me is tempted to just serialize/unserialize and compare the result to see if everything is accounted for. The rest of me is beating the pragmatic part of me down and hoping for a better solution.

apotonick commented 7 years ago

I understand - and I recommend you to check out how we handle that in Trailblazer or directly in Reform, where the form object applies a deserializing representer to itself. The representer per design has no knowledge about validations of any kind, but just parses values it knows to the form. The form then says "that's fine" or marks errors.

You can also override from_hash in every Representer and do the check there. The list of properties can be retrieved via Representer::definitions.