Railsで詰まったこと

前書き

neat02です。
今回はRealWorldで、APIでエンドポイントを作成しました。

環境

Rails 7.0.5 (API)

RealWorldとは

RailsやLaravelといったフレームワークの学習を目的に作られた、OSSのプロジェクトです。今回は、メディア記事の作成、詳細の閲覧、更新、削除のエンドポイントを作成しました。 必要なgemは 'active_model_serializers' です。

エンドポイントの作成の流れ

  1. モデルの作成
    このようなモデルを作成します。
class CreateArticles < ActiveRecord::Migration[7.0]
    def change
         create_table :articles do |t|
             t.string :slug
             t.string :title
             t.string :description
             t.text :body

             t.timestamps
          end
     end
end

2. コントローラーの作成 以下の通りです。

class ArticlesController < ApplicationController

  def create
    @article = Article.new(article_params)
    if @article.save
      render json: { article: ArticleSerializer.new(@article) }, status: :created
    else
      render json: { errors: @article.errors.full_messages }, status: :unprocessable_entity
    end
  end

  def show
    @article = Article.find_by(slug: params[:slug])
    render json: { article: ArticleSerializer.new(@article) }, status: :ok
  end

  def update
    @article = Article.find_by(slug: params[:slug])
    if @article.update(article_params)
      render json: { article: ArticleSerializer.new(@article) }, status: :ok
    else
      render json: { errors: @article.errors.full_messages }, status: :unprocessable_entity
    end
  end

  def destroy
    @article = Article.find_by(slug: params[:slug])
    @article.destroy
    head :no_content
  end

    private
  def article_params
    params.require(:article).permit(:title, :description, :body)
  end

end

3.ルートの設定 以下の通りです。

Rails.application.routes.draw do
  scope :api do
    resources :articles, param: :slug, only: %i[create]
    resources :articles, param: :slug, only: %i[show]
    resources :articles, param: :slug, only: %i[update]
    resources :articles, param: :slug, only: %i[destroy]
  end
end

私が詰まったのがシリアライザーです。 Serializerとは、データの入出力をモデルで橋渡しをする"クラス"のことです。 Serializerはコントローラーで、JSONで出力値を定義するのに用いました。 最初クラスということを知らずに、以下のように書いてしまいました。

class ArticlesController < ApplicationController

  def create
    @article = Article.new(article_params)
    if @article.save
      render json: { article: @article }, serializer: :ArticleSerializer,  status: :created
 ・・・

これだとrenderメソッドにSerializerが適用されません。 なぜなら、@article(オブジェクト)をSerializerに渡してないからです。 以下のように修正しました。

class ArticlesController < ApplicationController

 def create
     @article = Article.new(article_params)
     if @article.save
       render json: { article: ArticleSerializer.new(@article) }, status: :created
  ・・・

これで解決です。 ArticleSerializerクラスのインスタンスを作成し、それを@article(オブジェクト)に渡して、JSON形式に変換して出力できました。

修正前

{
        slug: "・・・"
        title:  "・・・・・ "
        description: "・・・・・"
        body:  "・・・・・”

}       

修正後

{ article: 
       {
        slug: "・・・"
        title:  "・・・・・ "
        description: "・・・・・"
        body:  "・・・・・”
        }
}