環境
'rails', '~> 6.0.0'
'capybara', '>= 2.15'
ruby '2.6.5'
はじめに
systemspecによる結合テストを行なっている際に、トップページレンダーした時に、以下のようなエラーが発生しました。
結論からお話しますと、このエラーはCapybaraのselectメソッドの記述ミスにより発生するものでした。
以下、エラーが発生した記述ではselectメソッドで’法規・条例’という文字をcategoryから探して選択するという記述をしているのですが、
実際の挙動としてはそこで選択した項目のidを引数として、トップページに渡すという作業をしています。
undefined method `[]' for nil:NilClass
とはselectメソッドで指定すべきidがありませんという内容と想定されます。
そのため、selectメソッドの中に引数となるidの番号を含めて記述しなくてはなりません。
エラーの原因となったコードを見てみますと、
select '法規・条例', from: 'tip_category_id'
となっておりますが、これをidを含めた形に修正すると、以下のようになります。
select Category.data[@tip.category_id - 1][:name], from: 'tip_category_id
Categoryモデルから@tipを引数にidを選択する記述に変更しました。
なお、activeHashは0から始まる番号で数字を選択するため、idとの関連性を考慮し、category_id -1 をしております。
以下、記述内容
エラー本文
Failure/Error: <p class="tiped-title-contents">カテゴリー : <%= Category.data[f.category_id][:name] %></p>
ActionView::Template::Error:
undefined method `[]' for nil:NilClass
[Screenshot]: /Users/taniguroarata/originalapp/archtips/tmp/screenshots/failures_r_spec_example_groups_nested_nested_visit_new_user_session_path_231.png
# ./app/views/tips/_main_area.html.erb:17:in `block in _app_views_tips__main_area_html_erb__1894181271776908624_70358077282820'
# ./app/views/tips/_main_area.html.erb:12:in `_app_views_tips__main_area_html_erb__1894181271776908624_70358077282820'
# ./app/views/tips/index.html.erb:10:in `_app_views_tips_index_html_erb___4391342711310590138_70357992921920'
# ------------------
# --- Caused by: ---
# NoMethodError:
# undefined method `[]' for nil:NilClass
# ./app/views/tips/_main_area.html.erb:17:in `block in _app_views_tips__main_area_html_erb__1894181271776908624_70358077282820'
spec/system/tips_spec.rb
require 'rails_helper'
RSpec.describe "投稿する", type: :system do
before do
@tip = FactoryBot.create(:tip)
@user = FactoryBot.create(:user)
end
context '投稿に成功した時' do
it 'visit new_user_session_path' do
visit new_user_session_path
fill_in 'user_email', with: @user.email
fill_in 'user_password', with: @user.password
find('input[type="submit"]').click
expect(current_path).to eq(root_path)
expect(page).to have_content('新規投稿')
visit new_tip_path
fill_in 'tip_title', with: @tip.title
select '法規・条例', from: 'tip_category_id' #ここがエラーの原因です
#以下のように修正します
select Category.data[@tip.category_id - 1][:name], from: 'tip_category_id
fill_in 'tip_description', with: @tip.description
binding.pry
expect{
find('input[type="submit"]').click
}.to change {Tip.count }.by(1)
expect(current_path).to eq(root_path)
end
end
end
app/views/tips/new.html.erb (テスト時の画面)
※画像の投稿は必須ではないため、今回は飛ばしてテストしております
<div class = "wrapper">
<%= render "shared/header" %>
<div class="main-tips-new">
<div class = "new-tip-string">
<p>新規投稿</p>
</div>
<%= form_with(model: @tip, local: true) do |form| %>
<%= render 'layouts/error_messages', model: form.object, class:"" %>
<div class="tip-title">
<p>タイトル</p>
<div class="tip-title-content">
<%= form.text_field :title, placeholder: "" %>
</div>
</div>
<div class="tip-category">
<p>カテゴリー</p>
<div class="tip-category-content">
<%= form.collection_select(:category_id, Category.all, :id, :name, {}, {class:""}) %> #ここにactiveHashを用いて、番号によって項目を、選択をしております。
</div>
</div>
<div class="tip-images">
<div class="tip-image-main">
<p class="tip-image-main-text">画像(メイン)</p>
<div id="image-list">
<%= form.file_field :image, class: 'tip-image-main-img' %>
</div>
</div>
<div class="tip-image-sub">
<p class="tip-image-sub-text">画像(サブ)</p>
<div class="tip-image-sub-images">
<%= form.file_field :image, class: 'tip-image-sub-img' %>
<%= form.file_field :image, class: 'tip-image-sub-img' %>
<%= form.file_field :image, class: 'tip-image-sub-img' %>
</div>
</div>
</div>
<div class="tip-description">
<p class="tip-description-text">説明</p>
<%= form.text_field :description, placeholder:"", class: 'text-form' %>
</div>
<%= form.submit "投稿する" %>
<% end %>
</div>
</div>
app/models/category.rb
class Category < ActiveHash::Base
self.data = [
{ id: 1, name: '--' },
{ id: 2, name: '法規・条例' },
{ id: 3, name: '納まり・詳細図' },
{ id: 4, name: '仕上げ' },
]
include ActiveHash::Associations
has_many :categories
end
終わりに
select等の要素を選択する際にはbinding.pryで値を確認しつつ行うとうまくいくことが多いです。
この記事が皆様のお役に立てればとおもいます。