Reputation: 6246
I have a controller returning a json structure like so:
def show
# .......
o_json = deep_object_1_to_json(o)
render :json => o_json
end
private
def deep_object_1_to_json(o)
o.to_json(
:include => {....})
end
Now I need to extend it to return 2 objects. However the obvious solution is giving me problems:
def show
# .......
o1_json = deep_object_1_to_json(o)
o2_json = deep_object_2_to_json(o)
render :json =>
{
:object_1 => o1_json,
:object_2 => o2_json
}
end
This returns a json object with 2 strings of escaped json data!
The deep_object_2_to_json functions already have several layers of nested includes so I would rather not have to refactor these into a single function. Is there a way to make this easily extendable to add more objects in the future without the double escaping problem above?
Thanks for any pointers.
Upvotes: 4
Views: 1505
Reputation: 84132
Sounds like you should be constructing something upon which to_json
can easily be called.
The obvious candidate for active record objects is as_json
. This does everything that to_json
does (include the :include
option and so on) except actually turning the object into json. Instead you get back a ruby hash which you can manipulate as you want and then call to_json. For example you could do
render :json => {
:o1 => object1.as_json(:include => :blah),
:o2 => object2.as_json(:include => :blah)
}
Upvotes: 7
Reputation: 17735
If you can refactor your class to return it's JSON via the to_json
method, you can simply stick two or more objects into an array and call to_json
on the array:
1.9.3-p125 :001 > require 'json'
=> true
1.9.3-p125 :002 > [{foo: "bar"}, {bar: "foo"}].to_json
=> "[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]"
Example:
def to_json
super(include: [:some_association])
end
Upvotes: 1
Reputation: 84338
Your controller shouldn't be serializing the object as JSON until right before it hands it off to be rendered.
In other words deep_object_1_to_json
should just be deep_object_1
. Then you can package both return values into an array or hash and render the as JSON.
def show
# .......
o1 = deep_object_1(o)
o2 = deep_object_2(o)
render :json =>
{
:object_1 => o1,
:object_2 => o2
}
end
It might be a pain to change it now, but for the future of your system, you really ought to be doing it this way. JSON is just a format for sending objects over the wire or to disk; none of your code should have any references whatsoever to JSON unless it is passing it off to be rendered.
Upvotes: 1