Recently we rolled out Representable 2.3. The main addition here is the ability to suppress wraps.
When talking about wraps, I am not referring to deliciously rolled flat bread filled with mouth-watering vegetables, grilled chicken and chilli sauce, no, I am thinking of container tags for documents.
Wraps, y’all!
Usually, you’d define the document wrap on the representer class (or module, but my examples are using Decorator
).
class SongDecorator < Representable::Decorator include Representable::Hash self.representation_wrap = :song # wrap set! property :name end
When rendering a Song
object, the document will be wrapped with "song"
.
song = Song.new(name: "I Want Out") SongDecorator.new(song).to_hash #=> {"song"=>{"name"=>"I Want Out"}}
Vice-versa, when parsing, the representer will only “understand” documents with the wrap present.
song = Song.new SongDecorator.new(song).from_hash({"song"=>{"name"=>"I Want Out"}})
I know, this is terribly fascinating.
Nested Representers
A popular concept in Representable and Roar is to nest representers. While this can be done with inline blocks, many people prefer explicitly nesting two or more classes.
class AlbumDecorator < Representable::Decorator include Representable::Hash self.representation_wrap = :albums # wrap set! collection :songs decorator: SongDecorator end
I reference the SongDecorator
explicitly. This allows me to use it in two places.
- To render and parse single song entities, I can use
SongDecorator
directly. - In a nested document with a list of songs, the same decorator can be used, given you desire an identical representation in the album view.
When rendering an album, however, every song is now wrapped.
album = Album.new(songs: [song, song]) AlbumDecorator.new(album).to_hash #=> {"albums"=> # {"songs"=>[ # {"song"=>{"name"=>"I Want Out"}}, # {"song"=>{"name"=>"I Want Out"}} # ]}}
Most probably not what you want.
I’ve seen several workarounds for this. Mostly, people maintain two decorators per entity, one with wrap, one without, where common declarations are shared using a module.
This is very clumsy and I do not understand why people take it instead of asking for a nice solution for that common problem. Maybe I’m not accessable enough.
Suppressing Wraps.
When working with Jonny on roarify, a client gem for the Shopify API and implemented using Roar, I dropped my inaccessible facade in exchange for beers and we implemented a solution: The wrap: false
option.
class AlbumDecorator < Representable::Decorator # .. collection :songs decorator: SongDecorator, wrap: false # no wrap! end
This will parse and serialize songs without wrapping them, again.
AlbumDecorator.new(album).to_hash #=> {"albums"=> # {"songs"=>[ # {"name"=>"I Want Out"}, # {"name"=>"I Want Out"} # ]}}
A simple enhancement with great impact – we were able to reduce representers by 38.1%.
Thanks for the beers, Jonnyboy! I miss you too!
Great addition! 🙂 Works wonders.
LikeLike