このページの内容は以下のリポジトリに1日遅れで反映されます(記事執筆前に前日分をコミットしています)。
https://github.com/hkob/hkob_blog
はじめに
Rails Tips の 77 回目です。昨日記事にユーザが追加されたので、ログインのテストを記述し自分の記事が作成できるようにしていきます。
ログインのテスト
まず、 Devise::Test::IntegrationHelpers
を spec/rails_helper.rb
の最後に追加します。その後、 login_user_fixture_as
と user_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_id
は articles/_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
は他人の記事を勝手に変更できないように確認する必要があります。明日はこのあたりの記事の所有権を含めて、モデルから修正していきます。