Wraps in Representable 2.3

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!

Advertisement

One thought on “Wraps in Representable 2.3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s