Mongoid: Object.to_json - how to load children objects as well? - ruby-on-rails

Mongoid doesn't include children documents into JSON when I do Object.to_json. How can I do it? I tried this:
#realty = Realty.includes(:comments).find(params[:id])
...
respond_to do |format|
format.json { render json: #realty }
end
But comments still doesn't get included in JSON.

You need to use :include in the to_json call
#realty = Realty.find(params[:id])
...
respond_to do |format|
format.json { render json: #realty.to_json(include: [:comments]) }
end
You can include any association in there.
You can also use any random method:
#foo.to_json(methods: [:some_arbitrary_method])
This works for a smaller/simple api but check out:
JBuilder, which is part of the Rails 4 default gem inclusion, obviously you can use this with any Rails version
ActiveModel Serializers

I am just working on something like this and I use:
gem "active_model_serializers"
https://github.com/rails-api/active_model_serializers
http://railscasts.com/episodes/409-active-model-serializers
in my case Project has_many :posts and the json result would be:
{"projects":[{"id":1,"title":"test project","description":"nice test project","slug":null,"posts":[{"id":1,"title":"new test post for test project","body":"Some content here and there","responses":[],"author":{"id":1,"email":"admin#mail.md"}}],"members":[]}]}
class ProjectSerializer < ActiveModel::Serializer
attributes :id, :title, :description, :slug
has_many :posts
has_many :memberships, key: :members
end
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body, :responses
end

Related

Why does the JSON patch data from relationships not get saved via Ruby on Rails?

I have an Ruby on Rails api where the data is handled in JSON. When I want to update an entity all the attributes are getting updated persistently but changed relationships arent' getting handled correctly, the entity stays the same as before.
JSON data before and after the PATCH:
{"data":{"id":"26","type":"candidate","attributes":
{"place":"Ort","zip_code":"PLZ","address":"Adresse",
"date_of_birth":"2019-01-01T00:00:00.000Z","title":"Frau",
"first_name":"Vorname","last_name":"Nachname",
"email_address":"email#example.ch",
"confirm_terms_and_conditions":true},"relationships":
{"occupational_fields":{"data":[]}}}}
PATCH input:
Started PATCH "/candidates/26" for 127.0.0.1 at 2019-01-22
19:40:53 +0100
Processing by CandidatesController#update as JSON
Parameters: {"data"=>{"id"=>"26", "attributes"=>{"place"=>"Ort",
"zip_code"=>"PLZ", "address"=>"Adresse", "title"=>"Frau",
"first_name"=>"Vorname", "last_name"=>"Nachname",
"email_address"=>"email#example.ch",
"confirm_terms_and_conditions"=>true, "date_of_birth"=>"2019-01-
01T00:00:00.000Z"}, "relationships"=>{"occupational_fields"=>
{"data"=>[{"type"=>"occupational-fields", "id"=>“4“}]}},
"type"=>"candidates"}, "id"=>"26", "candidate"=>{}}
This are my models, Candidates and OccupationalFields are related via a has_many belongs_to_many relationship through one CandidatesOccupationalField:
class Candidate < ApplicationRecord
has_many :candidates_occupational_fields, dependent: :destroy
has_many :occupational_fields, through:
:candidates_occupational_fields, dependent: :nullify
end
class CandidatesOccupationalField < ApplicationRecord
belongs_to :candidate
belongs_to :occupational_field
end
class OccupationalField < ApplicationRecord
has_many :candidates_occupational_fields, dependent: :destroy
has_many :candidates, through: :candidates_occupational_fields,
dependent: :nullify
end
This is the used controller:
class CandidatesController < ApplicationController
before_action :set_candidate, only: %i[show update destroy]
# GET /candidates
def index
#candidates = Candidate.all
render json: CandidateSerializer.new(#candidates).serialized_json
end
# GET /candidates/1
def show
#candidate = Candidate.find(params[:id])
render json: CandidateSerializer.new(#candidate).serialized_json
end
# POST /candidates
def create
#candidate = Candidate.new(candidate_params)
if #candidate.save
render json: CandidateSerializer.new(#candidate), status: :created
else
render json: #candidate.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /candidates/1
def update
#candidate = Candidate.find(params[:id])
if #candidate.update(candidate_params)
render json: CandidateSerializer.new(#candidate)
else
render status: :unprocessable_entity
end
end
# DELETE /candidates/1
def destroy
#candidate.destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_candidate
#candidate = Candidate.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def candidate_params
params.require(:data)[:attributes]
.permit(:place, :zip_code, :address,
:date_of_birth, :title, :first_name,
:last_name, :email_address,
:confirm_terms_and_conditions,
occupational_field_ids: [])
end
end
The JSON formatting is handled by fastjsonapi, this are the used serializers:
class CandidateSerializer
include FastJsonapi::ObjectSerializer
attributes :place, :zip_code, :address, :date_of_birth,
:title, :first_name, :last_name, :email_address,
:confirm_terms_and_conditions
has_many :occupational_fields
end
class OccupationalFieldSerializer
include FastJsonapi::ObjectSerializer
attributes :field
has_many :candidates
end
Thank you for your help.
The problem was, that the used serializer fast_jsonapi can't be used as deserializer and the Rail's strong parameters can't handle the json input. It works with the gem restful-jsonapi and modified params as shown in the example of the readme of restful-jsonapi.

how to define association in ActiveModel::Serializer

I have following Serializer
class BookSerializer < ActiveModel::Serializer
attributes :id, :name, :publisher, :author, :cover_url
has_many :chapters
end
I have two method in bookscontroller.rb file as follows:
def index
books = Book.select(:id, :name, :publisher, :publisher, :cover, :author)
if books.present?
render json: books
end
end
def show
book = Book.find_by_id params[:id]
render json: book
end
Actually everything is working fine but the problem is I want chapters records in show page not on index page, but right now query for fetching chapters are running in both action but I only want to include has_many :chapters in show action.
So Is there any way that can I use association for particular method in rails controller?
You can use different serializers for different actions. For example, remove has_many :chapters from BookSerializer and create a separate BookWithChaptersSerializer. Use it as follows:
class BookWithChaptersSerializer < ActiveModel::Serializer
attributes :id, :name, :publisher, :author, :cover_url
has_many :chapters
end
def show
book = Book.find_by_id params[:id]
render json: book, serializer: BookWithChaptersSerializer
end

Custom field in ActiveModel Serializer with another serializer

I have User model with has_many :sessions. But for one particular request I want to send only one session based on request device platform (iOS, Android).
The problem is that I have separate UserSerializer and UserSessionSerializer and I want to pass UserSessionSerializer as option in UserSerializer for :session field. Like this:
# UsersController
render json: #user, serializer: UserSerializer, session: #session # #user's session founded by platform
# UserSerializer
attributes :id, :email, :username, :session
def session
#instance_options[:session], serializer: UserSessionSerializer
end
It is impossible, because I can pass serializer only in has_one and has_many as I understand. But I don't want to render all user sessions in JSON with has_many, only founded one.
Thanks for any help!
Your code is good just use UserSessionSerializer.new instead of serializer: UserSessionSerializer
render json: { user: UserSerializer.new(#user, session: #session) }
attributes :id, :email, :username, :session
def session
UserSessionSerializer.new(self.instance_options[:session]) if self.instance_options[:session].present?
end

render multiple queries as json in rails controller

I have two rails controller actions:
def show
#project = Project.find(params[:id])
render json: #project,
:only => [:id, :compilation_id],
:methods => :track_name,
:include => {
:user => { :only => [:id, :email] }
}
end
def list_users
render json: User.select(:id, :email)
end
I would like to render them both in one response. What is the best way to go about doing this? I tried using the to_json method as described here but I read that that method is deprecated and I also noticed that it escapes the content which seems to be unnecessary. Any help is appreciated.
For the cases where you need json structures complicated enough for to_json to look readable, I recommend to use active_model_serializers gem.
You can then define two serializer classes like this:
class ProjectSerializer < ActiveModel::Serializer
attributes :id, :compilation_id
has_many :users
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
end
And then in your controller:
class ProjectsController < ApplicationController
def show
#project = Project.find(params[:id])
render json: #project, serializer: ProjectSerializer, status: 200
end
end
As a bonus track, you can even cache the response!
The solution, of course, was pretty simple:
project = Project.select(:id, :compilation_id, :user_id, :genre_id, :ordering).find(params[:id])
render json: { :project => project,
:users => User.select(:id, :email),
:genres => Genre.select(:id, :name),
:track_name => project.track_name
}

Include both joined tables in Rails JSON API call

I am getting the following Active Record Association error when trying to join two tables (with a polymorphic relationship) and include all data from both tables in a JSON API response:
Association named 'categories' was not found; perhaps you misspelled it?
Here is the controller action that I am trying to call:
def index
#items = Item.includes(:categories)
respond_to do |format|
format.json { render :json => #items.to_json }
end
end
And here are the two models that I am trying to join:
class Category < ActiveRecord::Base
attr_accessible :name
has_many :items, :as => :linkable
end
class Item < ActiveRecord::Base
attr_accessible :due_date, :linkable_id, :linkable_type, ...
belongs_to :linkable, :polymorphic => true, :counter_cache => true
end
Specifically, I want to return each Item in the database along with its Category. I have tried everything that I can think of. Any help will be greatly appreciated.
Have you tried :
def index
#items = Item.includes(:linkable).where(:linkable_type => 'Category')
respond_to do |format|
format.json { render :json => #items.to_json(include: :linkable) }
end
end
The name of your association is actually :linkable for the Item model, and not :categories (especially because it's a belongs_to so it would be :category).

Resources