Railsで詰まったこと
前書き
neat02です。
今回はRealWorldで、APIでエンドポイントを作成しました。
環境
RealWorldとは
RailsやLaravelといったフレームワークの学習を目的に作られた、OSSのプロジェクトです。今回は、メディア記事の作成、詳細の閲覧、更新、削除のエンドポイントを作成しました。 必要なgemは 'active_model_serializers' です。
エンドポイントの作成の流れ
- モデルの作成
このようなモデルを作成します。
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: "・・・・・” } }