rabl
rabl copied to clipboard
Child removes node from response when the provided object is an empty array
I have 2 different rabl templates and their actual outputs are provided below.
File 1: test.rabl
object false
child @test_objects => :test_objects do
attribute :object_id
end
node(false) do
node(:total) { 10 }
node(:pages) { 10 }
node(:page_no) { 1 }
end
This works as expected
> puts Rabl::Renderer.new('test', nil, format: :json, locals: { test_objects: [OpenStruct.new] }).render
{"test_objects":[{"test_object":{"object_id":70186699097320}}],"total":10,"pages":10,"page_no":1}
## With test_objects as empty array
> puts Rabl::Renderer.new('test', nil, format: :json, locals: { test_objects: [] }).render
{"test_objects":[],"total":10,"pages":10,"page_no":1}
File 2: test2.rabl
object false
child @test_objects, :root => :test_objects, :object_root => false do
attribute :object_id
end
node(false) do
node(:total) { 10 }
node(:pages) { 10 }
node(:page_no) { 1 }
end
The issue occurs when @test_objects is an empty array (2nd case). The test_objects
attribute doesn't make it to the final response.
> puts Rabl::Renderer.new('test2', nil, format: :json, locals: { test_objects: [OpenStruct.new] }).render
{"test_objects":[{"object_id":70186677972660}],"total":10,"pages":10,"page_no":1}
## With test_objects as empty array
> puts Rabl::Renderer.new('test2', nil, format: :json, locals: { test_objects: [] }).render
{"total":10,"pages":10,"page_no":1}
The only work around / hack that seems to work is if we change the definition of child
block to something like this
child({@test_objects => :test_objects}, {:root => :test_objects, :object_root => false}) do
In case this is accepted as a bug, the line that causes this behavior is here https://github.com/nesquena/rabl/blob/master/lib/rabl/builder.rb#L171
When first argument is hash (with empty array as the value), the data.present?
won't fail. This behavior is different obviously as it fails when empty array is passed as first argument.
I found that this check was introduced around 8 years back and I am not sure if it should be removed or not, so filing issue to discuss a better way to handle this scenario.
Anyone ? 🙂
The same problem occurs when a child is defined, but the given object ends up to be nil: the key will not be present in the response because of the early return mentioned above.
My suggestion would be to omit the key when the condition is not met (second branch of the conditional mentioned above). If the condition is met, an empty array or null value is returned if necessary.
Another - backward compatible solution - would be to allow a default value. (Although we would prefer a change as it makes an api more predictable and adds less burden on the developer who may forget to add a default on every child).
I can submit a PR if you want such a change.