Reputation: 133
i am trying to create an api for my mobile app.
I have posts
and images
tables. For my api, i can send all posts
with:
@posts = Post.all
render json: @posts
Output: [{"id":20,"title":"Title 1", "body":" first post ", "user_id":1 }]
But it does not contain images at all. In order to show a showcase image in homepage of my app, i just need the first image of associated images.
The output which i need is (the name of showcase_image
attribute does not matter) :
Output: [{"id":20, "title":"Title 1", "body":" first post ", "showcase_image": 'first_image.jpg' , "user_id":1 }]
I need to include first image from associated images table to my json response..
Thanks in advance !
Upvotes: 1
Views: 800
Reputation: 21120
You can include associations with the :include
option when calling as_json
.
render json: @posts.as_json(include: :images)
You could limit this to one image by adding a new association to Post
.
class Post < ApplicationRecord
has_many :images
has_one :showcase_image, class_name: 'Image'
end
This would allow you to use the :showcase_image
instead.
render json: @posts.as_json(include: :showcase_image)
You could also use Jbuilder to solve the issue at hand without adding an additional association.
# app/views/posts/index.json.jbuilder
# Get images that belong to posts, group them by post_id and
# return the minimum image id for each post_id.
images = Images.where(post_id: @posts.select(:id)).group(:post_id).minimum(:id)
# Request the full image data for all image ids returned above.
images = images.keys.zip(Image.find(images.values)).to_h
json.array! @posts do |post|
json.extract! post, :id, :title, :body, :...
json.showcase_image do
image = images[post.id]
if image
json.extract! image, :id, :name, :location, :...
else
json.null!
end
end
end
Without calling a specific render, Rails will default to the app/views/posts/index
file, and select the file matching the request. (If you request HTML it will look for an HTML file, if you request JSON it looks for JSON, etc.)
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
Now when you request /posts.json
or /posts
with the header Accept: application/json
your application should return the JSON response build by Jbuilder.
Upvotes: 0
Reputation: 182
I would suggest using a serializer. Active Model Serializer is pretty standard and easy to use, but is not receiving any updates and has a bad performance. You can choose any other serializer (I recommend Blueprinter) or use the AMS. Through the AMS you coudl define the relation you want to serialize and it would build the json you're expecting
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body, :showcase_image, :user_id
def showcase_image
object.images.first.name # don't know what is the attribute you're looking for
end
end
And on your controller:
@posts = Post.includes(:images).all # Use includes to avoid N+1 problems
render json: @posts, serialize_collection: PostSerializer
Upvotes: 3