representable
representable copied to clipboard
How To: Optionally wrap a lonely collection under a predefined key
I have following JSON decorator defined in my Rails 4 application for Event
model.
require 'representable/json'
class Json::EventRepresentation < Representable::Decorator
include Representable::JSON
property :id
property :data, render_nil: true
property :recorded_time
property :event_type_id
property :created_at
property :updated_at
end
I render a collection of Event
objects using Json::EventRepresentation.for_collection.new(@events).as_json
in my controller which emits following JSON array (which is a lonely collection)
[
{
"id": 49,
"data": null,
"recorded_time": "2015-04-02T21:23:16.509Z",
"event_type_id": 11,
"created_at": "2015-04-02T21:33:16.512Z",
"updated_at": "2015-04-02T21:33:16.512Z",
},
{
"id": 37,
"data": null,
"recorded_time": "2015-04-02T21:13:16.422Z",
"event_type_id": 10,
"created_at": "2015-04-02T21:33:16.424Z",
"updated_at": "2015-04-02T21:33:16.424Z",
}
]
However optionally at few places in my application I need to wrap the above shown lonely collection under key events
so that following JSON is emitted:
{
events: [
{
"id": 49,
"data": null,
"recorded_time": "2015-04-02T21:23:16.509Z",
"event_type_id": 11,
"device_id": 8,
"created_at": "2015-04-02T21:33:16.512Z",
"updated_at": "2015-04-02T21:33:16.512Z",
"client_id": 7
},
{
"id": 37,
"data": null,
"recorded_time": "2015-04-02T21:13:16.422Z",
"event_type_id": 10,
"device_id": 7,
"created_at": "2015-04-02T21:33:16.424Z",
"updated_at": "2015-04-02T21:33:16.424Z",
"client_id": 7
}
]
}
I am looking out for something like Json::EventRepresentation.for_collection.new(@events).as_json(wrap_in: :events)
if its supported.
I looked through the gem's test suite and the readme but couldn't get a hint to achieve the desired behavior. Can anybody please guide me on how do I achieve the desired behavior?
Thanks.
hey @jiggneshhgohel is Wrapping what you are looking for? You can pass a lambda to representation_wrap
to make it dynamic.
class Json::EventRepresentation < Representable::Decorator
self.representation_wrap = lambda do { |args| }
end
sorry @jiggneshhgohel. just realized that will probably not give you what you are looking for to add a key to your array. For collections, something like the following may be an option:
class EventsRepresenter < Representable::Decorator
collection :events,
:exec_context => :decorator,
:decorator => EventRepresenter
def events
represented
end
end
class EventRepresenter < Representable::Decorator
include Representable::JSON
property :id
property :data, render_nil: true
property :recorded_time
property :event_type_id
property :created_at
property :updated_at
end
EventsRepresenter.prepare(@events).to_json
{
events: [
{
"id": 49,
"data": null,
"recorded_time": "2015-04-02T21:23:16.509Z",
"event_type_id": 11,
"device_id": 8,
"created_at": "2015-04-02T21:33:16.512Z",
"updated_at": "2015-04-02T21:33:16.512Z",
"client_id": 7
},
{
"id": 37,
"data": null,
"recorded_time": "2015-04-02T21:13:16.422Z",
"event_type_id": 10,
"device_id": 7,
"created_at": "2015-04-02T21:33:16.424Z",
"updated_at": "2015-04-02T21:33:16.424Z",
"client_id": 7
}
]
}
@summera Thanks for the solution. It's really helpful.In fact I did thought of creating a separate representer for representing the lonely collection with few customizations for e.g using wrap option available on collection in a represented.
However I also thought that for such a trivial thing why should we be bothered about creating and maintaining a separate representer and there might be an alternative to achieve the desired results in a dynamic manner for e.g passing custom option like
Json::EventRepresentation.for_collection.new(@events).as_json(wrap_in: :events)
while rendering the json and using this option in Json::EventRepresentation in someway such that the given collection gets wrapped inside given key :events when the json gets rendered.@apotonick can you share your thoughts on this one?
@summera your solution is the way right now for me to continue and it also seems flexible enough for e.g when I need to add more data to the json which for now would be just containing events array wrapped under :events. For e.g
{ events: [ .....], custom_data_a: ..., custom_data_b: ..., ...}
But I really wish if there is out-of-the-box support for wrapping lonely collections under a given key , when needed, while rendering the json and hence avoiding the need to write and maintain a separate representer for the same.
Thanks, Jiggneshh
Uhm, but isn't what you're asking for exactly what ::representation_wrap
with a lambda does?
The problem here is that Representable tries hard to be a generic gem that explicitely does not solve everyone's requirements out-of-the-box, otherwise, this will end up like Rails.
I see your point, though, @jiggneshhgohel that it feels clunky to maintain two representers just to have a wrapping for the collections.
Maybe we should think about something as follows.
class Representer < ..
property :title
collection_representer do
self.representation_wrap ...
end
end
Here, you can configure specific items for the implicit collection representer. Cool?
@apotonick Thanks for such a prompt response. Using collection_representer
in the manner you have suggested definitely looks like a good solution. I would try it out.
Closing this for now.
Oh no, wait, this does not work, yet! :laughing: :rocket: