このページの内容は以下のリポジトリに1日遅れで反映されます(記事執筆前に前日分をコミットしています)。
https://github.com/hkob/hkob_blog
はじめに
Rails Tips の 60 回目です。昨日は、create による記事の追加を行いました。次に記事を更新するに書かれている edit と update を実装しましょう。
7.4 記事を更新する
こちらも先にテストを記述しましょう。update は create と同様に成功する場合と失敗する場合の二通りのテストが必要です。まだ shared_example に登録されていないものはこちらで紹介してあります。
- オブジェクト属性が変化した? shared_example : 小林研 Rails Tips (27)
- オブジェクト属性が変化しない? shared_example : 小林研 Rails Tips (28)
describe "GET #edit" do subject { -> { get edit_article_path(object) } } it_behaves_like "レスポンスコード確認", 200 it_behaves_like "描画結果に文字列が含まれている?", "記事の編集" end describe "PATCH #update" do subject { -> { patch article_path(object), params: {article: attrs} } } let(:return_path) { article_path(object) } context "正しいパラメータに対して" do before { attrs["title"] = "ABC" } it_behaves_like "レスポンスコード確認", 302 it_behaves_like "オブジェクト属性が変化した?", Article, :title, "ABC" it_behaves_like "リダイレクト確認" it_behaves_like "Notice メッセージ確認", "記事を更新しました。" end context "不正なパラメータに対して" do before { attrs["title"] = "" } it_behaves_like "レスポンスコード確認", 422 it_behaves_like "オブジェクト属性が変化しない?", Article, :title it_behaves_like "Alert メッセージ確認", "記事の更新に失敗しました。" end end
以前、show
で params[:id]
から @article
を取得していました。この処理は今回の edit
, update
、そしてこの後に説明する destroy
でも共通で実施します。そこで、 before_action
で共通処理で記載します。当初、destroy も入れていたのですが、Rails 7.1 からは記述していないメソッドを before_action
の only
に入れるとエラーが発生するようになっていました。RSPec だとこのエラーが見えなくてブラウザから確認して原因を理解しました。
before_action :take_one, only: %i[show edit update]
take_one
は private メソッドとして実装します。
private (中略) def take_one @article = object_from_params_id Article end
以前の show は中身がなくなります。
def show end
以前の edit も同じです。
def edit end
app/views/articles/edit.html.haml は new と内容が同じです。form は共通ですし、タイトルは翻訳テキストから取得されるためです。そもそもファイルを作ることもなく、シンボリックリンクにしてしまっていもいいかもしれません。
- content_for :title do - @page_title = t ".title" = render "form"
ja/locales/views/ja.yml
に以下のテキストを追加します。
edit: title: 記事更新 link_title: 編集
残りは update の実装です。基本的に create とほとんど変わりません。save と update の違いくらいです。
def update if @article.update(article_params) redirect_to @article, notice: notice_message(Article) else flash.now[:alert] = alert_message Article render :edit, status: :unprocessable_entity end end
これで edit
, update
のテストおよび実装が完了しました。RSpec の結果は以下のようになっています。無事に全てのテストが通過しています。
GET #edit behaves like レスポンスコード確認 レスポンスのステータスが 200 であること behaves like 描画結果に文字列が含まれている? レスポンスの文字列が「記事更新」を含むこと PATCH #update 正しいパラメータに対して behaves like レスポンスコード確認 レスポンスのステータスが 302 であること behaves like オブジェクト属性が変化した? is expected to change `klass.find(object.id).send(key)` from "This is the second article that can be deleted" to "ABC" behaves like リダイレクト確認 is expected to redirect to "/articles/158250001" behaves like Notice メッセージ確認 notice に「記事を更新しました。」が出力されること 不正なパラメータに対して behaves like レスポンスコード確認 レスポンスのステータスが 422 であること behaves like オブジェクト属性が変化しない? Article の title が変化しないこと behaves like Alert メッセージ確認 alert に「記事の更新に失敗しました。」が出力されること Finished in 0.2431 seconds (files took 1.72 seconds to load) 22 examples, 0 failures
おわりに
edit, update が完了したので、記事が更新できるようになりました。明日は最後の destroy まで実装します。