Reputation: 5693
Context: ruby "2.0.0" and rails "4.0.0"
I am wondering how to return more data than a simple JSON representation of my model. I have this method in my API controller:
def show
@entry = params[:id].to_i != 0 ? Entry.find(params[:id]) : Entry.where(slug: params[:id]).first
respond_with @entry
end
which returns a well formatted JSON article when called via http://pow.url.dev/en/tenant/api/v1/entries/23
.
I also have two other method to get the next and previous article, for instance, next
looks like this:
def next
@current_entry = params[:entry_id].to_i != 0 ? Entry.find(params[:entry_id]) : Entry.where(slug: params[:entry_id]).first
@entry = Entry.where( status_id: 0 ).where( "published_at > ?", @current_entry.published_at ).first
respond_with @entry
end
The problem is that the client application needs to make 3 API calls to 1) fetch an article, 2) fetch the next article and 3) fetch the previous article.
It would be much better if the client had to do only one call to get all the information at once.
I would like to add into the show
method the Title and ID of the next and previous article along with the JSON result, what would be the best way to do that?
Upvotes: 0
Views: 1173
Reputation: 5693
Here is the solution I came up with:
Implementing two methods in the Entry model object for next
and previous
as follows:
def next
Entry.where( status_id: 0 ).where( "published_at > ?", self.published_at ).select('id, title, slug').first
end
def previous
Entry.where( status_id: 0 ).where( "published_at < ?", self.published_at ).select('id, title, slug').last
end
and replace respond_with
by render :json
in the show
action of my controller:
def show
@entry = params[:id].to_i != 0 ? Entry.find(params[:id]) : Entry.where(slug: params[:id]).first
render :json => @entry.to_json(:include => :entry_fields,
:methods => [:next, :previous])
end
Output:
{
"id": 20,
"title": "Video Test",
"slug": "video-test",
"status_id": 0,
"promoted": true,
"published_at": "2014-01-20T11:51:00.000Z",
"created_at": "2014-01-20T11:51:37.406Z",
"updated_at": "2014-03-05T13:42:49.981Z",
"excerpt": "Video",
"user_id": "933dc175-0d73-45fb-9437-61ecc4f55705",
"next": {
"id": 21,
"title": "Test Multiple",
"slug": "test-multiple"
},
"previous": {
"id": 18,
"title": "Example Entry",
"slug": "example-entry"
},
...
... (associations)
...
}
Upvotes: 1
Reputation: 5015
Quick and dirty:
def show
@entry = ...
render :json => @entry.attributes.merge({
:next_id => id_of_next_article,
:next_title => title_of_next_article...
})
end
More flexible solution: use some sort of JSON serialization customizers (or roll your own), one I've used before is ActiveModel Serializers (https://github.com/rails-api/active_model_serializers). I'm sure there are others.
Upvotes: 3
Reputation: 1901
Will the user always use the Next and the Prev articles? If so, put them together on the JSON, otherwise, use link location tags with REL to prev
and next
on the returning JSON, then the clint will be able to know where to get the next
and prev
articles. You can get more info: RESTful Web Service usage of custom link relations - 'rel'
Upvotes: 1