How do I serialize habtm relationships in Ruby on Rails with fast_jsonapi

532 views Asked by At

I created a Ruby on Rails API application where I wanted to implement a JSON api with fast_jsonapi. Now I'm struggling with the relationships, which aren't shown. What do I have to change?

This is my schema.db:

create_table "candidates", force: :cascade do |t|
  t.string "place"
  t.string "zip_code"
  t.string "address"
  t.string "date_of_birth"
  t.string "title"
  t.string "profile_picture"
  t.string "first_name"
  t.string "last_name"
  t.string "email_address"
  t.boolean "confirm_terms_and_conditions"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "candidates_degrees", id: false, force: :cascade do |t|
  t.bigint "candidate_id"
  t.bigint "degree_id"
  t.index ["candidate_id"], name: "index_candidates_degrees_on_candidate_id"
  t.index ["degree_id"], name: "index_candidates_degrees_on_degree_id"
end

create_table "degrees", force: :cascade do |t|
  t.string "degree"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

And these are my models:

class Candidate < ApplicationRecord
  has_and_belongs_to_many :degrees, dependent: :nullify
end

class Degree < ApplicationRecord
  has_and_belongs_to_many :candidates, dependent: :nullify
end

These are my serializers:

class CandidateSerializer
  include FastJsonapi::ObjectSerializer
  attributes :place, :zip_code, ...
  has_many :degrees
end

class DegreeSerializer
  include FastJsonapi::ObjectSerializer
  attributes :degree
  has_many :candidates
end
2

There are 2 answers

0
Rohit Lingayat On BEST ANSWER

you need to do changes in your CandidateSerializer and DegreeSerializer.

Instead of writing the separate HABTM relation in serializer you can directly right in attributes

e.g

class CandidateSerializer
  include FastJsonapi::ObjectSerializer
  attributes :place, :zip_code,:degrees
end

response

{
  :data=>
    {:id=>"",
     :type=>:candidate,
     :attributes=> {   
       degrees: {}
     }
 }

same for DegreeSerializer

  class DegreeSerializer
    include FastJsonapi::ObjectSerializer
    attributes :candidates
  end
0
Vítor Ribas Bandeira On

You can do this:

class CandidateSerializer
  include FastJsonapi::ObjectSerializer
  attributes :place, :zip_code,...
  has_many :degrees, if: Proc.new { |record| record.association(:dregrees).loaded? }
end
class DegreeSerializer
  include FastJsonapi::ObjectSerializer
  has_many :candidates, if: Proc.new { |record| record.association(:candidates).loaded? }
end

And in your API action (here for example with show route):

def show
  @candidate.degrees.load
  render json: CandidateSerializer.new(@candidate, options).serialized_json if stale?(@candidate)
end

private

def set_candidate
  @candidate = Candidate.find_by(id: params[:id])
end

def options
  { include: [:degrees] }
end

Result:

{
    "data": {
        "id": "20",
        "type": "candidate",
        "attributes": {
            "id": 20,
            ...
        },
        "relationships": {
            "degrees": {
                "data": [
                    {
                        "id": "713",
                        "type": "degree"
                    }
                ]
            }
        }
    },
    "included": [
        {
            "id": "713",
            "type": "degree",
            "attributes": {
                "id": 713,
                ...
            },
            "relationships": {}
        }
    ]
}