Have you ever had the need to not only fetch a single models data but the data included in that models relationships with other models?
Using Rails as a backend API server we can hone in on the data we want to render and send to our front end application. Say we have the following relationships:
USER:
has_many :comments
has_many :posted_pets, :class_name => "Pet", :foreign_key => "user_id"
has_many :pets, through: :comments
PET:
belongs_to :user
has_many :comments, dependent: :delete_all
has_many :users, through: :comments
COMMENTS:
belongs_to :user
belongs_to :pet
These relationships establish that a user has many posted pets using an alias and has many comments that belong to a pet.
Our need at the front end side of the application is that we want to display a pet with their list of comments and an individual comment will display the comments users username like below:
Our first task is to render the pet model data, but we want to establish what we want to render to the front end of the application. To do so we use a serializer. To create a serializer using Rails we need to include the following in our terminal rails g serializer pet
. You will notice that the name of the serializer "pet" is singular. This follows the proper naming convention to ensure this serializer is used as the default serializer for the "Pet" model. Lets take a look at the now generated serializer for "pet".
The serializer allows us to control the attributes that will be rendered to the front end. Say we have a found address attribute that we do not want to display in the front end of the application. We can exclude this attribute in the serializer to keep the data from being rendered.
Now this serializer is being used when we fetch our Pet model data. Here is a glimpse of the controller rendering the data to the front end application.
def show
pet = Pet.find_by(id: params[:id])
if pet
render json: pet,
else
render json: {error: "Pet not found"}, status: :not_found
end
end
We however are not done. Looking back at our front end image we can see that we require the comments data that is associated with the pet. We already established our relationships in our models but now we can utilize our serializer to include the associated data when we render. Like so:
Now we get the pet data and all the comment data associated with the pet. We can stop here but lets say we want to also control the comment data we render to the front end. To do so we create another serializer for the comment model using our rails g serializer comment
. Lets see how this looks below:
Utilizing this serializer we are only included each comments ":id" and ":body" when rendering the data. No additional syntax is needed in our pet controller:
def show
pet = Pet.find_by(id: params[:id])
if pet
render json: pet,
else
render json: {error: "Pet not found"}, status: :not_found
end
end
We have our pet data and our comment data, but now we need the user that posted the comment's username. To do this we have to include more syntax in our controller because AMS or active model serializer is not able to render deeply nested data.
A simple fix is to "include:" the data in our pet controller like so:
def show
pet = Pet.find_by(id: params[:id])
if pet
render json: pet, include: ['comments', 'comments.user']
else
render json: {error: "Pet not found"}, status: :not_found
end
end
Establishing the relationships and utilizing AMS we can finally render the following data to our front end:
What an amazing functionality! I hope this helped you learn more about AMS.
Top comments (0)