skip to Main Content

I have an author that has many books and a book that belongs to an author in an rails 7 api. I am using "jsonapi-serializer", "~> 2.2" to try and get the author and their books. When I look at the json file, I get this:

{
  "id": "1",
  "type": "author",
  "attributes": {
    "id": 1,
    "fname": "John",
    "lname": "Doe"
  },
  "relationships": {
    "books": {
      "data": [
        {
          "id": "1",
          "type": "books"
        },
        {
          "id": "2",
          "type": "books"
        },
        {
          "id": "3",
          "type": "books"
        },
        {
          "id": "4",
          "type": "books"
        },
        {
          "id": "5",
          "type": "books"
        }
      ]
    }
  }
}

I want to expand what is in relationships to show the full information or at least customize it so that it shows something like id, name, release_year rather than just id and type. I don’t want to have to make another database query to get the books.

The AuthorSerializer looks like this:

class AuthorSerializer
  include JSONAPI::Serializer
  attributes :id, :fname, :lname
  has_many :books
end

The BookSerializer looks like this:

class BooksSerializer
  include JSONAPI::Serializer
  attributes :id, :name, :release_year, :awards, :genre, :price, :blurb, :isbn
  belongs_to :author
end

The Author controller looks like this:

class AuthorController < ApplicationController
  before_action :set_author, only: %i[ show update destroy ]

  # GET /authors
  def index
    @authors = Author.includes(:books).all

    render json: AuthorSerializer.new(@authors)
  end

  # GET /authors/1
  def show
    render json: AuthorSerializer.new(@author)
  end

  # POST /authors
  def create
    @author = Author.new(hospital_params)

    if @author.save
      render json: @author, status: :created, location: @author
    else
      render json: @author.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /authors/1
  def update
    if @author.update(author_params)
      render json: @author
    else
      render json: @author.errors, status: :unprocessable_entity
    end
  end

  # DELETE /authors/1
  def destroy
    @author.destroy
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_author
      @author= Author.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def author_params
      params.require(:author).permit(:id, :fname, :lname, :avatar[])
    end
end

2

Answers


  1. There are lots of ways you can get associated data from the associated model in Ruby on rails:

    I just share two ways:

    1. You can use as_json

    example:

    user.as_json(include: { posts: {
                           include: { comments: {
                                          only: :body } },
    

    More details: See Here

    1. You can use ruby-grape gem. You can get associated data and it has lots of customization. Just look at the documentation. Grape Gem

    If you have any confusion, let me know. Thank you.

    Login or Signup to reply.
  2. What you are asking for violates the JSON:API spec.

    relationships: a relationships object describing relationships between the resource and other JSON:API resources.

    “relationship object” MUST contain at least one of the following:

    data: resource linkage

    Resource linkage MUST be represented as one of the following:

    an array of resource identifier objects for non-empty to-many relationships.

    A “resource identifier object” is an object that identifies an individual resource.

    A “resource identifier object” MUST contain a type member. It MUST also contain an id member…
    A “resource identifier object” MAY also include a meta member, whose value is a meta object that contains non-standard meta-information.

    As you can see a Resource Identifier cannot contain anything more than type, id, and meta (other than non persisted objects which must contain lid in place of id)

    The jsonapi-serializer gem strictly adheres to the spec and only returns the "Resource Identifier Objects" i.e. type and id (Code Source)

    You could use AuthorSerializer.new(@authors, include: [:books]) which will add the Book objects to the included member but it is definitely not the cleanest representation

    Example:

    {:data=>
      {:id=>"1",
       :type=>:author,
       :attributes=>{:id=>1, :fname=>"John", :lname=>"Doe"},
       :relationships=>
        {:books=>
          {:data=>
            [{:id=>"1", :type=>:book},
             {:id=>"2", :type=>:book},
             {:id=>"3", :type=>:book},
             {:id=>"4", :type=>:book},
             {:id=>"5", :type=>:book}]}}},
     :included=>
      [{:id=>"1",
        :type=>:book,
        :attributes=>{:id=>1, :name=>"Book 1", :release_year=>2011},
        :relationships=>{:author=>{:data=>{:id=>"1", :type=>:author}}}},
       {:id=>"2",
        :type=>:book,
        :attributes=>{:id=>2, :name=>"Book 2", :release_year=>2012},
        :relationships=>{:author=>{:data=>{:id=>"1", :type=>:author}}}},
       {:id=>"3",
        :type=>:book,
        :attributes=>{:id=>3, :name=>"Book 3", :release_year=>2013},
        :relationships=>{:author=>{:data=>{:id=>"1", :type=>:author}}}},
       {:id=>"4",
        :type=>:book,
        :attributes=>{:id=>4, :name=>"Book 4", :release_year=>2014},
        :relationships=>{:author=>{:data=>{:id=>"1", :type=>:author}}}},
       {:id=>"5",
        :type=>:book,
        :attributes=>{:id=>5, :name=>"Book 5", :release_year=>2015},
        :relationships=>{:author=>{:data=>{:id=>"1", :type=>:author}}}}
      ]}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search