Rails 7: jsonapi-serializer にネストされた関連付けを含める方法
概要
Rails 7 APIには、多くの本を持っている著者と、その著者に属する本があります。私は「jsonapi-serializer」、「~> 2.2」を使用して著者とその書籍を取得しようとしています。 json ファイルを見ると、次のようになります。
{
"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"
}
]
}
}
}
関係にあるものを展開して完全な情報を表示するか、少なくとも ID とタイプだけではなく ID、名前、リリース年などを表示するようにカスタマイズしたいと考えています。本を取得するために別のデータベース クエリを作成する必要はありません。
AuthorSerializer は次のようになります。
class AuthorSerializer
include JSONAPI::Serializer
attributes :id, :fname, :lname
has_many :books
end
BookSerializer は次のようになります。
class BooksSerializer
include JSONAPI::Serializer
attributes :id, :name, :release_year, :awards, :genre, :price, :blurb, :isbn
belongs_to :author
end
Author コントローラーは次のようになります。
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
解決策
あなたが求めているものは JSON:API 仕様に違反しています。
ご覧のとおり、リソース識別子には、タイプ、ID、メタ以外のものを含めることはできません (ID の代わりに蓋を含める必要がある非永続オブジェクトを除く)
jsonapi-serializer gem は仕様に厳密に従っており、「リソース識別子オブジェクト」、つまりタイプと ID (コード ソース) のみを返します。
Book オブジェクトをインクルードされたメンバーに追加する AuthorSerializer.new(@authors, include: [:books]) を使用することもできますが、これは明らかに最もクリーンな表現ではありません
例:
{: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}}}}
]}