編集フォームでの更新テストを自動化しよう
学習の目標
本章では、以下の内容を学習します。
- Railsアプリケーションにおける編集機能の基本的な実装方法について、コントローラからビューまでの一連の流れを体系的に理解する
- 既存のレコードを安全に更新するための設計パターンと、Strong Parametersを活用したセキュアな実装手法を習得する
- システムスペックにおける事前データの準備方法と、beforeブロックを使用した効率的なテストコードの書き方を学ぶ
- 一覧画面から編集画面への遷移、データの更新、エラー処理など、実際のユーザー操作を想定したテストシナリオの組み立て方を実践的に理解する
はじめに
前回はバリデーションのテストについて学習しました。 新規作成機能では、空のデータにユーザーが情報を入力する流れでしたが、実際のWebアプリケーションでは、既存のデータを修正する編集機能も重要な要素です。
本章では、既存のTodoを編集する機能のテストを実装していきます。 編集機能では、既存データの取得、フォームでの表示、更新処理という一連の流れをテストすることになります。
編集機能の実装
まずはコントローラの実装から始めましょう。 編集機能では、データの表示と更新の2つのアクションが必要になります。
コントローラの実装
app/controllers/todos_controller.rbを開きます。 前回のrails generateコマンドで、editアクションとupdateアクションの雛形は作られていますが、実装はまだ行われていません。
これらのアクションを以下のように実装していきます。
class TodosController < ApplicationController  # 既存のアクション(index, new, create)は省略
  def edit    @todo = Todo.find(params[:id])  end
  def update    @todo = Todo.find(params[:id])    if @todo.update(todo_params)      redirect_to todos_path    else      render :edit    end  end
  private
  def todo_params    params.require(:todo).permit(:title, :description)  endendコントローラの動作解説
このコードについて説明していきましょう。
editアクションでは、URLのパラメータ(id)を使って編集対象のTodoを取得します。 このTodoは、編集用フォームで使用されます。
updateアクションでは、同じくURLのパラメータからTodoを取得し、フォームから送信されたデータで更新を試みます。 更新に成功したら一覧画面に戻り、失敗した場合は編集画面を再表示します。
編集フォームの作成
次に、編集用のビューファイルを作成します。 app/views/todos/edit.html.erbを開きます。
これも雛形が生成されていますが、実装はまだ行われていないため、以下のように実装していきます。
<h1>Todo編集</h1>
<% if @todo.errors.any? %>  <div class="error-messages">    <h2><%= @todo.errors.count %>件のエラーがあります</h2>    <ul>      <% @todo.errors.full_messages.each do |message| %>        <li><%= message %></li>      <% end %>    </ul>  </div><% end %>
<%= form_with(model: @todo, local: true) do |f| %>  <div>    <%= f.label :title, 'タイトル' %>    <%= f.text_field :title %>  </div>  <br>  <div>    <%= f.label :description, '説明' %>    <%= f.text_area :description %>  </div>  <div>    <%= f.submit '更新' %>  </div><% end %>
<%= link_to '一覧に戻る', todos_path %>このフォームは、新規作成のフォームとほぼ同じ構造です。 主な違いは、タイトルが「Todo編集」になっていることと、送信ボタンのラベルが「更新」に変更されている点です。
一覧画面への編集リンクの追加
続いて、一覧画面から編集画面へ移動できるように、リンクを追加します。 ユーザーが直感的に編集操作を行えるようにするためです。
app/views/todos/index.html.erbを開いて、各Todoの表示部分に編集リンクを追加します。
<h1>Todo一覧</h1>
<div class="todos">  <% @todos.each do |todo| %>    <div class="todo">      <h2><%= todo.title %></h2>      <p><%= todo.description %></p>      <p>        状態: <%= todo.completed ? "完了" : "未完了" %>        <%= link_to '編集', edit_todo_path(todo) %>      </p>    </div>  <% end %></div>
<%= link_to '新規作成', new_todo_path %>動作確認
では、bundle exec rails sでサーバーを起動して、編集機能が正しく動作するか確認してみましょう。
bundle exec rails sブラウザでhttp://localhost:3000/todosにアクセスし、以下の操作を行います。
まず、一覧画面に表示されているTodoの「編集」リンクをクリックします。 次に、タイトルと説明を変更してみましょう。 最後に、「更新」ボタンをクリックします。
一覧画面に戻り、変更した内容が反映されていることを確認します。 動作確認ができたら、Ctrl+Cでサーバーを停止します。
編集機能のテストの実装
実際の動作が確認できたので、これをテストコードで表現していきましょう。 編集機能では、既存データの準備、編集画面への遷移、データの更新という流れをテストします。
spec/system/todos_spec.rbに編集機能のテストを追加します。
require 'rails_helper'
RSpec.describe 'Todo管理', type: :system do  # 既存のテストは省略...
  describe '編集' do    # テストで使用するTodoを準備    before do      @todo = Todo.create!(        title: 'テスト駆動開発',        description: 'アプリケーションをテスト駆動で実装する'      )    end
    it 'Todoを編集できる' do      # Todo一覧画面を表示      visit todos_path
      # 編集リンクをクリック      click_link '編集'
      # フォームに新しい値を入力      fill_in 'タイトル', with: 'RSpec入門'      fill_in '説明', with: 'システムスペックについて理解を深める'
      # 更新ボタンをクリック      click_button '更新'
      # 一覧画面に遷移していることを確認      expect(current_path).to eq todos_path
      # 変更した内容が表示されていることを確認      expect(page).to have_content('RSpec入門')      expect(page).to have_content('システムスペックについて理解を深める')    end
    it '編集画面で不正な値を入力するとエラーメッセージが表示される' do      # 編集画面を表示      visit edit_todo_path(@todo)
      # 不正な値を入力      fill_in 'タイトル', with: ''  # タイトルを空に      fill_in '説明', with: '短すぎ'  # 説明を10文字未満に
      # 更新ボタンをクリック      click_button '更新'
      # エラーメッセージが表示されることを確認      expect(page).to have_content('Title can\'t be blank')      expect(page).to have_content('too short')    end  endendテストコードの詳細解説
このテストについて説明していきましょう。
テストデータの準備
まずbeforeブロックを使用してテストで使用するTodoを作成し、後に編集画面を表示するときのために@todoというインスタンス変数に格納しています。 このTodoは、各テストケースで必要になったときに利用できるように準備されます。
正常系のテスト
次に、正常系と異常系の2つのテストケースを実装しました。
正常系のテストでは以下の点を確認しています。
まず、一覧画面から編集画面に移動できることを確認します。 次に、フォームに新しい値を入力できることをテストします。 最後に、更新後に一覧画面に戻り、変更が反映されていることを検証します。
異常系のテスト
異常系のテストでは以下の点を確認しています。
バリデーションエラーが正しく機能することを検証します。 また、エラーメッセージが適切に表示されることも確認します。
テストの実行
では、テストを実行してみましょう。
$ bundle exec rspec spec/system/todos_spec.rb
Todo管理  Todo一覧を表示する  新規Todoを作成できる  バリデーション    タイトルと説明が未入力の場合、エラーメッセージが表示される    説明が10文字未満の場合、エラーメッセージが表示される    エラー後、正しい入力で登録できる  編集    Todoを編集できる    編集画面で不正な値を入力するとエラーメッセージが表示される
Finished in 0.12487 seconds (files took 0.89012 seconds to load)7 examples, 0 failures全てのテストが成功しました!これにより、編集機能が期待通りに動作していることが確認できます。
まとめ
本章では、編集機能の実装とそのテストについて学習しました。
具体的には以下の点をテストできるようになりました。 まず、Todo一覧画面から編集画面への遷移ができることを確認できます。 次に、編集フォームでの値の更新が正しく行えることを検証できます。 そして、バリデーションエラーが適切に処理されることも確認できます。
編集機能のテストでは、既存データの準備から更新処理まで、一連の流れを包括的にテストできました。
Basicプランでより詳しく学習
この先のコンテンツを読むにはBasicプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。