Torihaji's Growth Diary

Little by little, no hurry.

色々使ってみてわかったイチオシのRails Serializer

はじめに

みなさん、こんにちは torihaziです

今日はタイトル通り 数あるRailsのSerializerのgemを色々使ってみて

どれが自分にとって使いやすいかを検証していこうと思います。

メンテがされてるされてない、重い重くないとかは気力があったら書いていきます。

とにかく使いやすいか否か。

ここでいう使いやすいか否かの判断基準は 定義とかfrontendでの取り出し方とかです

前提条件

筆者はfrontendから useSWR x axiosを使ってデータを取得しようとしています。

そのためレスポンスの形は

interface AxiosResponse<T = any> {
  data: T;          // 実際のレスポンスデータ
  status: number;
  statusText: string;
  headers: any;
  config: any;
}

こんな感じで帰ってきます。これを前提としてbackendでSerializer使ってきます

エントリーNo.1 jsonapi-serializer(fast_jsonapi)

GitHub - jsonapi-serializer/jsonapi-serializer: A fast JSON:API serializer for Ruby (fork of Netflix/fast_jsonapi)

gemfileに

gem 'jsonapi-serializer'

してbundle installした後にapp/serializers/ファイル名_serializer.rb作って

# frozen_string_literal: true

class TweetIndexWithImagesSerializer
  include JSONAPI::Serializer

  set_type :tweet

  attribute :id, :content, :image_urls
end

とする。

でcontrollerで

      def index
        tweets = Tweet.all
        json_string = TweetIndexWithImagesSerializer.new(tweets).serializable_hash
        render json: { message: '成功', data: json_string }, status: :ok
      end

みたいにして呼ぶとレスポンスは

data: { 
    data: {
        data: {
            0: {
                id: 数字
                type: tweet
                attributes: {
                    content: "hoge"
                    image_urls: [~~~~,~~~・・・]
                }
           }
           ,・・・・
         }
     }
}

何個data のkeyがあるんじゃい。

1個目はaxiosのdata、2個目は rails のcontrollerで定義したやつ、3個目はjsonapi-serializerのやつ。

あとserializerでactivestorageのurl返す時詰まったら下記を参照

Serializerで画像のurlをjsonで返す際に発生したエラー #Ruby - Qiita

ok。次。

エントリーNo2 activemodel-serializer

色々触ろうと思いましたが、GithubのReadmeに「いったん開発やめるわ」みたいなこと書いてあったので却下。

ただ代替案をご丁寧に書いてくれていたのでそれをみてみることに。

エントリーNo3 jsonapi-rails

代替案1つ目らしいっす。

Start by adding the following to your Gemfile:

gem 'jsonapi-rails'
Then, once your serializable resources are defined, building a JSON API document from your business objects is straightforward: simply pass them to the render method.

gem入れて

render jsonapi: Tweet.all てすればいけるらしいけど。

ドキュメント見てわかったけど、ドキュメントがしょぼい気がする。

不親切といった感じ。自分の読解力がないだけかもしれない。

とりあえず使ってみて、使い方は2つ?あるっぽい。使い方が悪いのかもしれないけど

app/serializers/serializable_tweet.rb作って

# app/serializable/serializable_tweet.rb
class SerializableTweet < JSONAPI::Serializable::Resource
  type 'tweets'

  attributes :content, :image_urls  # 必要な属性を指定
  

  # 関連付けがある場合
  # has_one :user
  # has_many :likes
end

てした後に コントローラで

render jsonapi: Tweet.all

て感じで呼び出すと

data: { 
    data: {
        0: {
            id: 数字
            type: tweets (<= typeで設定した時の文言、してなければunknown)
            attributes: {
                content: "hoge"
                image_urls: [~~~~,~~~・・・]
            }
       }
       ,・・・・
     },
    jsonapi: ・・・
}

attributesていうのは出るっぽい。ちなみに前みたいに

render json: {jsonapi: Tweet.all, message: "成功"}

てやったとしてもなんかいけた。

そうしたら

data: { 
    jsonapi: {
        0: {
            id: 数字
            content: "hoge"
            created_at: 
            updated_at: 
       }
       ,・・・・
     },
}

モデルTweetが持つ全カラムが出力されたが、image_urlsが消えた。あとtypeの記載も。

attributesも消えたけどなんかバグっぽい。

これもないかな。

エントリーNo4 jsonapi_resources

jsonapi-resources.com

んーよくわからん。

次。

エントリーNo 5 alba

名前かっこいい。笑

それに最高。

求めてた形で帰ってきた。

設定方法はこれを参照

【Rails】AlbaでAPI実装

config/initializer/alba.rbに

# alba.rb
Alba.backend = :active_support
Alba.inflector = :active_support

てして

app/resources/base_resource.rbに

class BaseResource
  include Alba::Resource
end

app/resources/tweets_with_images_resource.rbに

class TweetsWithImagesResource < BaseResource
  root_key :tweet <= 対象のモデル

  attributes :id, :content, :image_urls
end

ちなみにimage_urlsはtweet.rbにおいてこう定義してる。

# frozen_string_literal: true

class Tweet < ApplicationRecord
  include Rails.application.routes.url_helpers

  belongs_to :user
  has_many_attached :images

  def image_urls
    images.map { |image| url_for(image) } if images.attached?
  end
end

コントローラは

tweets = Tweet.all
render json: {message: '成功', data: TweetsWithImagesResource.new(tweets)}

としたらレスポンスは

data: { 
    data: {
        0: {
            id: 数字
            content: "hoge"
            image_urls: [~~~~,~~~・・・]
        }
      ,・・・・
     }
}
config: ・・・

みたいな感じで理想のができた

attributesとかも出てないし、typeも出てないし。

君に決めた!

終わりに

長きにわたる最適なRails Serializer探しの旅終了。

選ばれたのは albaでした。

github.com

異論認めますが、いったんこの子を採用して個人開発進めます。

ということで。