2

I am using Ruby on Rails 4 and the RABL gem. I would like to reuse templates by rendering the show.json.rabl view from the index.json.rabl and keep convention stated at jsonapi.org (source: RABL documentation).

That is, I have the following files:

# index.json.rabl
collection @articles => :articles
attributes :id, :title, :...

# show.json.rabl
collection [@article] => :articles
attributes :id, :title, :...

Since for each article instance the index.json.rabl renders the same attributes as for the show.json.rabl I would like to reuse the latter as partial template, or (maybe) to extend the first.

What I would like to output is:

# index JSON output
{"articles":[{"id":1,"title":"Sample 1","...":...},{"id":2,"title":"Sample 2","...":...},{"id":3,"title":"Sample 3","...":...}]}

# show JSON output
{"articles":[{"id":1,"title":"Sample 1","...":...}]}
Backo
  • 18,291
  • 27
  • 103
  • 170

3 Answers3

2

Here is a neat way:

things/base.rabl:

attributes :id, :title
child(:another_child, :object_root => false) { attributes :id, :title }

things/show.rabl:

object @thing
extends 'things/base'

things/index.rabl:

collection @things
extends 'things/base'
Raj
  • 22,346
  • 14
  • 99
  • 142
0

You can use extends - https://github.com/nesquena/rabl/wiki/Reusing-templates

object @post

child :categories do
  extends "categories/show"
end
  • 2
    Can you provide a complete answer including an example with `show.json.rabl` and `index.json.rabl` views. – Backo May 24 '14 at 09:31
0

I was having trouble interpreting what I needed to do from https://github.com/nesquena/rabl/wiki/Reusing-templates but finally figured it out. For me, I had files structured like this: (names changed to protect the innocent ;) )

/app/controllers/api/my/boring_things_controller.rb
/app/views/api/my/boring_things/index.json.rabl
/app/controllers/api/my/interesting_things_controller.rb
/app/views/api/my/interesting_things/index.json.rabl

boring_things/index.json.rabl looked like this (except for real, it had a LOT more attributes):

collection @boring_things, :root => :things, :object_root => false
attributes :id,
           :name,
           :created_at,
           :updated_at

And interesting_things/index.json.rabl looked ALMOST identical:

collection @interesting_things, :root => :things, :object_root => false
attributes :id,
           :name,
           :created_at,
           :updated_at

I wanted to reuse just the attribute parts. The confusing part to me about https://github.com/nesquena/rabl/wiki/Reusing-templates was that I didn't really think I needed a 'node', and I didn't think I needed 'child' either because I wanted the attributes at the top level, not as a child object. But it turns out I did need 'child'. Here's what I ended up with:

/app/controllers/api/my/boring_things_controller.rb
/app/views/api/my/boring_things/index.json.rabl
/app/controllers/api/my/interesting_things_controller.rb
/app/views/api/my/interesting_things/index.json.rabl
/app/views/api/my/shared/_things.json.rabl

_things.json.rabl is this:

attributes :id,
           :name,
           :created_at,
           :updated_at

boring_things/index.json.rabl is now this:

child @boring_things, :root => :things, :object_root => false do
  extends "api/my/shared/_things"
end        

and interesting_things/index.json.rabl is now this:

child @interesting_things, :root => :things, :object_root => false do
  extends "api/my/shared/_things"
end        

So for you, instead of rendering show from index, I'd try doing something where you extract article attributes out into a rabl file shared by index and show. In the same directory where your show.json.rabl and index.json.rabl are (I'm assuming it's views/articles/index.json.rabl and views/articles/show.json.rabl), create a "_article_attributes.json.rabl" file. Sorry I don't have your exact setup so I can't try it out myself syntactically, but it should be something like this in your index.json.rabl:

child @articles do
  extends "articles/_article_attributes"
end

[A side note: Another thing that tripped me up when I was doing this was that since my shared file was in a sibling-directory to the different rabl files that used them and I was trying to use a relative path and that did NOT work. Instead I had to use the path starting with whatever's under "app/views" (i.e. "extends 'api/my/shared/_things'" not "extends '../shared/_things'"). That was a weird situation and I won't go into why we did it that way, but if you can it's better to have the shared file in the same directory as your index and show, like you're doing.]

Gayle
  • 3,053
  • 3
  • 20
  • 13