記事を1件作成する(続き): 小林研 Rails Tips (59)

このページの内容は以下のリポジトリに1日遅れで反映されます(記事執筆前に前日分をコミットしています)。

https://github.com/hkob/hkob_blog

はじめに

Rails Tips の 59 回目です。昨日は、new による追加画面を作成しました。この form の結果を受けて記事を作成する create を実装しましょう。

Rails をはじめよう - Railsガイド

7.3 記事を1件作成する

こちらも先にテストを記述しましょう。create は成功する場合と失敗する場合の二通りのテストが必要です。まだ shared_example に登録されていないものはこちらで紹介してあります。

  let!(:attrs) { object.attributes }

  describe "POST #create" do
    before { object.destroy }
    subject { -> { post articles_path, params: {article: attrs} } }
    let(:return_path) { article_path(Article.order(created_at: :desc).first) }
    context "正しいパラメータに対して" do
      it_behaves_like "レスポンスコード確認", 302
      it_behaves_like "オブジェクトが1増えるか?", Article
      it_behaves_like "リダイレクト確認"
      it_behaves_like "Notice メッセージ確認", "記事を登録しました。"
    end

    context "不正なパラメータに対して" do
      before { attrs["title"] = "" }
      it_behaves_like "レスポンスコード確認", 422
      it_behaves_like "オブジェクト数が変化しない?", Article
      it_behaves_like "Alert メッセージ確認", "記事の登録に失敗しました。"
    end
  end

create action は Strong parameter の article_params を呼び出し、new で作成した記事を保存します。保存に成功した場合、作成した記事のページにリダイレクトします。逆に失敗した場合には、new を再描画します。

def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to @article, notice: notice_message(Article)
    else
      flash.now[:alert] = alert_message Article
      render :new, status: :unprocessable_entity
    end
  end

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

ここで notice_message とalert_message のための翻訳テキストは config/localtes/views/ja.yml に以下のように設定します。

  flash:
    create:
      notice: "%{obj}を登録しました。"
      alert: "%{obj}の登録に失敗しました。"
    update:
      notice: "%{obj}を更新しました。"
      alert: "%{obj}の更新に失敗しました。"
    edit:
      alert: "%{obj}を編集する権限がありません。"
    destroy:
      notice: "%{obj}を削除しました。"
      alert: "%{obj}を削除する権限がありません。"
    show:
      alert: "%{obj}を表示する権限がありません。"
    copy:
      notice: "%{obj}を一括コピーしました。"
    duplicate:
      notice: "%{obj}を複製しました。"
    edit_status:
      create: "編集を開始します。"
      update: "編集状態を解除しました。"
    remove_all:
      notice: "%{obj}を全て削除しました。"
    append_all:
      notice: "%{obj}を一括登録しました。"
    update_all:
      notice: "%{obj}を一括更新しました。"
    permission_error:
      alert: "ページを表示する権限がありません。"

あとは application_controller.rb に alert_message と notice_message の実装を追加するだけです。

  # @param [Class] klass 表示するクラス
  # @return [String] 表示する alert message
  # @see https://hkob.hatenablog.com/entry/2023/12/17/050000
  def alert_message(klass, acn = nil)
    I18n.t "flash.#{acn || action_name}.alert", **{obj: klass.model_name.human}
  end

  # @param [Class] klass 表示するクラス
  # @return [String] 表示する notice message
  # @see https://hkob.hatenablog.com/entry/2023/12/17/050000
  def notice_message(klass, acn = nil)
    I18n.t "flash.#{acn || action_name}.notice", **{obj: klass.model_name.human}
  end
  helper_method :notice_message

これで create のテストおよび実装が完了しました。POST #create の RSpec の結果は以下のようになっています。無事に全てのテストが通過しています。

  POST #create
    正しいパラメータに対して
      behaves like レスポンスコード確認
        レスポンスのステータスが 302 であること
      behaves like オブジェクトが1増えるか?
        Article.count が 1 つ増えること
      behaves like リダイレクト確認
        is expected to redirect to "/articles/655299031"
      behaves like Notice メッセージ確認
        notice に「記事を登録しました。」が出力されること
    不正なパラメータに対して
      behaves like レスポンスコード確認
        レスポンスのステータスが 422 であること
      behaves like オブジェクト数が変化しない?
        Article.count が変化しないこと
      behaves like Alert メッセージ確認
        alert に「記事の登録に失敗しました。」が出力されること

おわりに

create が完了したので、新しい記事が投稿できるようになりました。edit はほとんど new と変わらないので、明日は update まで実装します。