I hear a lot of misunderstandings related to RABL, templates, testing and more. This page is an attempt to help clarify a few of those issues. Before criticizing RABL, please read this guide to try to understand how it works.
Serialization should be testable and RABL isn't easily testable
We 100% agree that serialization should be testable. RABL templates are testable both inside and outside of a web request context. Keep reading below for examples using
Rabl.render to do standalone unit testing as well as examples of easy functional testing. RABL supports both.
RABL can't be used for generating push notifications or for background jobs
Not at all true, many people use RABL for these purposes. Simply use
Rabl.render to render templates within any context. Rabl works quite well outside of a controller context.
RABL requires ActionView, Rails, or a controller to function
See above. This is simply not at all true. Simply use
Rabl.render to render templates in any context. RABL can be used quite well outside of a controller context.
Object serialization doesn't belong in templates
JSON and XML are data exchange formats and they do fundamentally represent a view of your data not unlike an HTML view or any other view format. JSON rendering in an API is a view of your data, there's no way around that. Moreso, even in other contexts outside of a controller the template is rendering an object into a representation. A ruby-based DSL such as RABL is a great way to create these representations. In addition, with RABL you can render into JSON, XML, Plist, MsgPack, et al using the same consistent templating language.
RABL templates can become complicated
As with all views, templates should not contain intricate object and model logic or complex conditionals. Views are intended to be simple representations of your objects and this is where RABL fits well into the picture. If you are worried about RABL views getting complex, you should apply best practices and extract RABL partials to reduce code duplication as with any view and use presenters to organize the code correctly. Check out David's excellent post on presenters to see how to simplify complex API templates.
Partials can be misused or make templates overly complicated
As with all views, partials can be used well or overused. Partials are simply a way to separate out common bits of a view for use in multiple places. Used well, partials remove code duplication and support DRY API generation. Most APIs will have the same objects displayed in many different places and contexts, and partials can be a valuable tool. RABL also supports template inheritance through
extends which makes having multiple templates (say one for admin users and one for regular users) exceptionally simple. As with anything, partials can be misused, but this is true for almost any coding construct.
Here's an example of both functional and unit testing with RABL. You often do not need to do both, just test either one depending on your needs. If you are only using RABL for APIs check out the functional or integration testing. If you are using templates in order to serialize for non-API uses, check unit testing. Mix and match basically depending on your needs.
Test the API response (if template is used an API generation):
require File.expand_path(File.dirname(__FILE__) + '/../test_config.rb') describe "Post Controller" do setup do @post = Factory.generate(:body => "foo") get :show, :id => @post.id @result = JSON.parse(last_response.body) end it "should render post body" do assert_equal "foo", @result['post']['body'] end it "should be have other keys" do assert_same_elements ['body', 'user_id', 'title'], @result['post'].keys end end
or use unit tests to validate serialization (if template is used for serializing outside API generation):
require File.expand_path(File.dirname(__FILE__) + '/../test_config.rb') describe "Post Serialization" do setup do @post = Factory.generate(:body => "foo") @result = Rabl::Renderer.render(@post, 'posts/show', :format => :hash) end it "should render post body" do assert_equal "foo", @result['post']['body'] end it "should be have other keys" do assert_same_elements ['body', 'user_id', 'title'], @result['post'].keys end end
Also helpful to checkout our guide on managing complexity with presenters. RABL does not have to be at odds with using presenters. Exactly the opposite, they are best used together in conjunction. RABL to generate the view structure for JSON, XML, Plist, MsgPack, et al and then the complex logic and state managed where they belong in the presenters and models.
The bottom line is that JSON and XML are data exchange formats but they do fundamentally represent a view of your data not unlike an HTML view or any other format. View templates should not contain object and model logic or complex conditionals. Views are intended to be simple representations of your objects and this is where RABL fits into the picture. RABL works with Sinatra, Rails, Padrino and even outside the context of a web application with standalone rendering.