ログインのテスト: 小林研 Rails Tips (77)

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

https://github.com/hkob/hkob_blog

はじめに

Rails Tips の 77 回目です。昨日記事にユーザが追加されたので、ログインのテストを記述し自分の記事が作成できるようにしていきます。

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

ログインのテスト

まず、 Devise::Test::IntegrationHelpersspec/rails_helper.rb の最後に追加します。その後、 login_user_fixture_asuser_login のメソッドを追加します。ユーザが気にするのは後者の user_login のみとなります。

  # for Request Spec
  config.include Devise::Test::IntegrationHelpers, type: :request
end

def login_user_fixture_as(key)
  @one = users key
  sign_in @one
end

def user_login(key)
  before { login_user_fixture_as key }
  after { sign_out @one }
end

これから articles_spec を修正していきます。まず、ログインしていなくても index や show は閲覧して欲しいので、 when not login コンテキストで括ります。

  context "when not login" do
    describe "GET #index" do
      subject { -> { get articles_path } }
      it_behaves_like "レスポンスコード確認", 200
      it_behaves_like "描画結果に文字列が含まれている?", %w[記事一覧 タイトル]
    end

    describe "GET #show" do
      subject { -> { get article_path(object) } }
      it_behaves_like "レスポンスコード確認", 200
      it_behaves_like "描画結果に文字列が含まれている?", %w[This is the second article]
    end
  end

例外は後回しにしてまず動く方のテストを先に作ってみましょう。ログインしている場合には、 current_user の記事を作成できるようにします。先ほど用意した user_login を使ってログインしたのち、current_user で new や create を実施します。new と create のテストは特に変更する点はありません。

  context "when login by hkob" do
    user_login :hkob

    describe "GET #new" do
      subject { -> { get new_article_path } }
      it_behaves_like "レスポンスコード確認", 200
      it_behaves_like "描画結果に文字列が含まれている?", %w[記事作成 タイトル 本文]
    end

    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

次に articles_controller.rb を修正します。まず、先ほどの index, show はログインの必要がないので、:authnticate_user! の除外にします。逆にいうとそれ以外のメソッドは全部認証が必要になります。

class ArticlesController < ApplicationController
  before_action :authenticate_user!, except: %i[index show]

new は user_id が必要になります。current_user でログインしているユーザが取得できるので、そのユーザの articles で build することで新規データを作成することができます。

  def new
    @article = current_user.articles.build
  end

ここで設定された user_idarticles/_form.html.haml 内の form_with で渡される必要があるため、hidden_field として渡されるようにします。

= form_with model: @article do |f|
  %table
    %thead
      %tr
        %th 項目
        %th 内容
    %tbody
      - %i[title body status].each do |attr|
        %tr
          %td= form_label_and_error f, @article, attr
          %td
            - case attr
            - when :title
              = f.text_field attr
            - when :status
              = f.select attr, Article::VALID_STATUSES
            - else
              = f.text_area attr, rows: 10, cols: 80
      %tr
        %td{colspan: 2}
          = f.hidden_field :user_id
          = f.submit

テストは create でエラーになっています。これは article_params に user_id が含まれていないためです。これを追加することでエラーが回避されます。

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

おわりに

create は権限の問題がないので、テストに変更はありませんでした。edit は他人の記事を勝手に変更できないように確認する必要があります。明日はこのあたりの記事の所有権を含めて、モデルから修正していきます。