質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

Q&A

解決済

1回答

815閲覧

結合テストで`ActionView::Template::Error: undefined method `if_1' for nil:NilClass`になってしまうのを解消したい。

cherry2020

総合スコア10

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

0グッド

0クリップ

投稿2021/02/14 05:55

編集2021/02/14 07:14

実現したいこと

  • 現在、オリジナルアプリを作っています。
  • 下記のような画面遷移で結合テストを成功させたいのですが、エラーになってしまいます。

habits/index.html.erbにリンク先があり、「イフゼンルールの設定」を押すとrules/index.html.erbへ遷移。
(1枚目の画像:上)
rules/index.html.erbにおいて必要事項を入力し保存。
(2枚目の画像)
③保存が完了すると、habits/index.html.erbに遷移し、保存した内容が表示される。
(1枚目の画像:真ん中)
イメージ説明
イメージ説明

バージョン

  • Rails 6.0.3.4
  • rspec-rails (4.0.2)

エラー内容

terminal

1MacBook-Air action_app % bundle exec rspec spec/system/rules_spec.rb 2 3イフゼンルールの設定 4 イフゼンルールの設定ができる場合 5DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the :nickname attribute in User model, pass `case_sensitive: true` option explicitly to the uniqueness validator. (called from block (2 levels) in <top (required)> at /Users/○/projects/action_app/spec/system/rules_spec.rb:11) 6DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the :email attribute in User model, pass `case_sensitive: true` option explicitly to the uniqueness validator. (called from block (2 levels) in <top (required)> at /Users/○/projects/action_app/spec/system/rules_spec.rb:11) 7 新規投稿後、保存され、習慣カウントページへ遷移するとイフゼンルールが表示される (FAILED - 1) 8 イフゼンルールの設定ができない場合 9DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the :nickname attribute in User model, pass `case_sensitive: true` option explicitly to the uniqueness validator. (called from block (2 levels) in <top (required)> at /Users/○/projects/action_app/spec/system/rules_spec.rb:11) 10DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the :email attribute in User model, pass `case_sensitive: true` option explicitly to the uniqueness validator. (called from block (2 levels) in <top (required)> at /Users/○/projects/action_app/spec/system/rules_spec.rb:11) 11 新規投稿後、保存できず、入力ページにとどまる (FAILED - 2) 12 13Failures: 14 15 1) イフゼンルールの設定 イフゼンルールの設定ができる場合 新規投稿後、保存され、習慣カウントページへ遷移するとイフゼンルールが表示される 16 Failure/Error: <p><%= @rule.if_1 %></p> 17 18 ActionView::Template::Error: 19 undefined method `if_1' for nil:NilClass 20 21 [Screenshot]: /Users/○/projects/action_app/tmp/screenshots/failures_r_spec_example_groups_nested_nested_新規投稿後、保存され、習慣カウントページへ遷移するとイフゼンルールが表示される_80.png 22 23 24 # ./app/views/habits/index.html.erb:19:in `block in _app_views_habits_index_html_erb___4534987002136358121_70092370747140' 25 # ./app/views/habits/index.html.erb:4:in `_app_views_habits_index_html_erb___4534987002136358121_70092370747140' 26 # ------------------ 27 # --- Caused by: --- 28 # NoMethodError: 29 # undefined method `if_1' for nil:NilClass 30 # ./app/views/habits/index.html.erb:19:in `block in _app_views_habits_index_html_erb___4534987002136358121_70092370747140' 31 32 2) イフゼンルールの設定 イフゼンルールの設定ができない場合 新規投稿後、保存できず、入力ページにとどまる 33 Failure/Error: <p><%= @rule.if_1 %></p> 34 35 ActionView::Template::Error: 36 undefined method `if_1' for nil:NilClass 37 38 [Screenshot]: /Users/○/projects/action_app/tmp/screenshots/failures_r_spec_example_groups_nested_nested_2_新規投稿後、保存できず、入力ページにとどまる_387.png 39(上記と同じエラー 文字数制限に引っかかってしまい省略) 40 41Finished in 5.34 seconds (files took 2.72 seconds to load) 422 examples, 2 failures 43 44Failed examples: 45 46rspec ./spec/system/rules_spec.rb:15 # イフゼンルールの設定 イフゼンルールの設定ができる場合 新規投稿後、保存され、習慣カウントページへ遷移するとイフゼンルールが表示される 47rspec ./spec/system/rules_spec.rb:52 # イフゼンルールの設定 イフゼンルールの設定ができない場合 新規投稿後、保存できず、入力ページにとどまる

テストコード

###spec/system/rules_spec.rbの内容

ruby

1require 'rails_helper' 2 3def basic_pass 4 username = ENV['BASIC_AUTH_USER'] 5 password = ENV['BASIC_AUTH_PASSWORD'] 6 visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}" 7end 8 9RSpec.describe 'イフゼンルールの設定', type: :system do 10 before do 11 @user = FactoryBot.create(:user) 12 # @rule = FactoryBot.create(:rule) 13 end 14 context 'イフゼンルールの設定ができる場合' do 15 it '新規投稿後、保存され、習慣カウントページへ遷移するとイフゼンルールが表示される' do 16 # basic_passのメソッドを実行 17 basic_pass 18 # spec/support/log_in_support.rbより、ログインに関するメソッドの呼び出し 19 log_in(@user) 20 # 習慣ページへ遷移 21 visit habits_path 22 # 習慣ページには「イフゼンルールの設定」へのリンクがある 23 expect(page).to have_content('イフゼンルールの設定') 24 # 「イフゼンルールの設定」ボタンをクリックする 25 click_link 'イフゼンルールの設定' 26 # イフゼンルールのページへ遷移する 27 visit rules_path 28 # フォームにそれぞれ入力する 29 fill_in 'rule_if_1', with: '食事のイフルール' 30 fill_in 'rule_then_1', with: '食事のゼンルール' 31 fill_in 'rule_if_2', with: '睡眠のイフルール' 32 fill_in 'rule_then_2', with: '睡眠のゼンルール' 33 fill_in 'rule_if_3', with: '運動のイフルール' 34 fill_in 'rule_then_3', with: '運動のゼンルール' 35 fill_in 'rule_if_4', with: '学びのイフルール' 36 fill_in 'rule_then_4', with: '学びのゼンルール' 37 fill_in 'rule_if_5', with: 'マインドのイフルール' 38 fill_in 'rule_then_5', with: 'マインドのゼンルール' 39 # 保存ボタンをクリックする 40 click_on '保存' 41 # 保存ボタンを押すとイフゼンルール設定のカウントが1上がることを確認する 42 expect { 43 find('input[name="commit"]').click 44 }.to change { Rule.count }.by(1) 45 # 目標一覧ページへ遷移する 46 expect(current_path).to eq habits_path 47 # 保存されたイフゼンルールが表示されていることを確認する  48 expect(page).to have_content '食事のイフルール' ⭐️これを一旦削除しても同じエラーが出る 49 end 50 end 51 context 'イフゼンルールの設定ができない場合' do 52 it '新規投稿後、保存できず、入力ページにとどまる' do 53 # basic_passのメソッドを実行 54 basic_pass 55 # spec/support/log_in_support.rbより、ログインに関するメソッドの呼び出し 56 log_in(@user) 57 # 習慣ページへ遷移 58 visit habits_path 59 # 習慣ページには「イフゼンルールの設定」へのリンクがある 60 expect(page).to have_content('イフゼンルールの設定') 61 # 「イフゼンルールの設定」ボタンをクリックする 62 click_link 'イフゼンルールの設定' 63 # イフゼンルールのページへ遷移する 64 visit rules_path 65 # フォームにそれぞれ入力する 66 fill_in 'rule_if_1', with: '食事のイフルール、12文字以上の設定' 67 fill_in 'rule_then_1', with: '食事のゼンルール、12文字以上の設定' 68 fill_in 'rule_if_2', with: '睡眠のイフルール、12文字以上の設定' 69 fill_in 'rule_then_2', with: '睡眠のゼンルール、12文字以上の設定' 70 fill_in 'rule_if_3', with: '運動のイフルール、12文字以上の設定' 71 fill_in 'rule_then_3', with: '運動のゼンルール、12文字以上の設定' 72 fill_in 'rule_if_4', with: '学びのイフルール、12文字以上の設定' 73 fill_in 'rule_then_4', with: '学びのゼンルール、12文字以上の設定' 74 fill_in 'rule_if_5', with: 'マインドのイフルール、12文字以上の設定' 75 fill_in 'rule_then_5', with: 'マインドのゼンルール、12文字以上の設定' 76 # 保存ボタンをクリックする 77 click_on '保存' 78 # 保存ボタンを押してもイフゼンルール設定のカウントが上がらないことを確認する 79 expect { 80 find('input[name="commit"]').click 81 }.to change { Rule.count }.by(0) 82 # イフゼンルールのページに留まっていることを確認する 83 expect(current_path).to eq rules_path 84 end 85 end 86end

spec/factories/rules.rbの内容

ruby

1FactoryBot.define do 2 factory :rule do 3 association :user 4 association :habit 5 if_1 { '12文字以内のルール' } 6 then_1 { '12文字以内のルール' } 7 if_2 { '12文字以内のルール' } 8 then_2 { '12文字以内のルール' } 9 if_3 { '12文字以内のルール' } 10 then_3 { '12文字以内のルール' } 11 if_4 { '12文字以内のルール' } 12 then_4 { '12文字以内のルール' } 13 if_5 { '12文字以内のルール' } 14 then_5 { '12文字以内のルール' } 15 end 16end 17

#エラー内容を見て確認したこと

NoMethodError(undefined method 'if_1' for nil:NilClass)となっている、
/app/views/habits/index.html.erb:19行目は以下のようになっています。

検証キーで、htmlにソースを確認すると、2つ目のようになっています。

ruby

1 <div> 2 <p><%= @rule.if_1 %></p> 3 <p><%= @rule.then_1 %></p> 4 </div>

html

1 <div> 2  <p>いふ</p> 3 <p>ゼン</p> 4 </div>

また、インスタンス変数については、app/controllers/habits_controller.rbのindexアクションにおいて、以下のように定義しています。

ruby

1class HabitsController < ApplicationController 2 before_action :authenticate_user! 3 4 def index 5 @habit = Habit.new 6   (省略) 7 @rule = Rule.where(user_id: current_user.id).last →⭐️このように定義 8 end 9 10(省略)

habitsテーブルと、rulesテーブルは1対1の関係でアソシエーションを組んでいます。

ruby

1class Habit < ApplicationRecord 2 belongs_to :user 3 has_one :rule 4end

ruby

1class Rule < ApplicationRecord 2 belongs_to :user 3 belongs_to :habit, optional: true 4(省略) 5end

教えていただきたいこと

  • ブラウザ上で、保存されたデータが反映されるにも関わらず、テストコード上のメソッドがnilになってしまうのは何故でしょうか?

 (ファクトリーボットや、before doにおいて、別の前提定義が足りていないのでしょうか?)

  • 確かに、rulesテーブルにおいて、habits_idを保存しているわけではないので(インスタンス変数で定義したものを表示しているだけ)なのですが、それを結合テストにどう落とし込めばいいのか、調べているのですが分かりません。
  • 今回の結合テストにおいて、クリックした後に画面遷移をし、保存ができ、反映されることを実装したいのですが、テストコードを実行すると、ログイン後、habitsの画面に遷移した時点で、エラーになってしまっている部分も理由もよく分かりません。

どうぞよろしくお願いします。

追記 

保存ボタンを押した時のコード(createアクションの動き)

ruby

1class RulesController < ApplicationController 2 def index 3 @rule = Rule.new 4 end 5 6 def create 7 @rule = Rule.new(rule_params) 8 if @rule.save 9 redirect_to habits_path 10 else 11 render 'index' 12 end 13 end 14 15 private 16 17 def rule_params 18 params.require(:rule).permit(:if_1, :if_2, :if_3, :if_4, :if_5, :then_1, :then_2, :then_3,:then_4, :then_5).merge(user_id: current_user.id) 19 end 20end
spec/support/log_in_support.rbのコード(ユーザーがログインした時の動き)

ruby

1module LogInSupport 2 # ログインを前提とする結合コードにて使用するため 3 def log_in(user) 4 visit new_user_session_path 5 fill_in 'email', with: user.email 6 fill_in 'password', with: user.password 7 find('input[name="commit"]').click 8 expect(current_path).to eq "/habits.#{user.id}" 9 end 10end 11
spec/factories/users.rbのコード
FactoryBot.define do factory :user do nickname { Faker::Games::Pokemon.name } email { Faker::Internet.unique.email } # ランダムで生成する際、英数字になるよう'1a'追加 password { '1a' + Faker::Internet.unique.password(min_length: 15) } password_confirmation { password } birthdate { Faker::Date.birthday } end end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/02/14 06:06

保存ボタンを押して呼び出されるアクションのコードはどのようになっていますか?
suama

2021/02/14 06:42

便乗ですが、違ってたらすみません。 HabitsController#index の処理の @rule = Rule.where(user_id: current_user.id).last の結果が無いので、/app/views/habits/index.html.erb でエラーになっていると思うのですが、 ユーザに対応するルールは、事前にどこかで登録する必要があるのでしょうか? もし必要ならFactoryBotで追加するといいと思うので、合わせて教えていただければ...
cherry2020

2021/02/14 07:18

maisumakunさん、ありがとうございます。createアクションのことであっていますでしょうか?上記に追記しました。 suamaさん、ありがとうございます。インスタンス変数に定義した結果とはどのように表現するのでしょうか?ユーザーは、deviseを使って、新規登録・ログインをしています。ログインをしなければ、ログイン後の画面へ遷移できないようhabitsコントローラーにおいて「before_action :authenticate_user!」を定義しています。(回答になっていますでしょうか・・?)テストコードに関しては、サポートモジュールを使い、ログインに関する部分だけ別で作っています。
suama

2021/02/14 07:59 編集

maisumakunさまへのコメントに便乗してしまい、すみません。 気になったのが、specのエラーの箇所が 「rspec ./spec/system/rules_spec.rb:15」の通り15行目になっているので、 そもそも 「click_link 'イフゼンルールの設定'」を踏まえてルールを設定して、redirect_to habits_path されるところではなくて、そこに到達する以前の、 ``` # spec/system/rules_spec.rb の15行目 # 習慣ページへ遷移 visit habits_path ``` のところでエラーになっている、という点でした m(_ _)m
cherry2020

2021/02/14 09:07

suamaさん、ありがとうございます。 はい>< Habitsに行く前にエラーになってしまう原因が何故なのか分からず苦慮しておりました。 コメントいただき、嬉しかったです。 ありがとうございました。
guest

回答1

0

ベストアンサー

@rule = Rule.where(user_id: current_user.id).last
これが nil すなわち@userは未だ一つもRuleを作っていない、ということです。

ブラウザーでみる画面は development のDBです。test のDBはそれとは別なので、 @user = FactoryBot.create(:user) した新しいuserにはRuleは空 # @rule = FactoryBot.create(:rule) とコメントアウトしてるからですね。
多分エラーになったのでしょう
@rule = FactoryBot.create(:rule, user_id: @user.id) としてみてください。

ただ、、、、
新規ユーザーにはRuleはやはり無いはずなので、その対策も必要だ、ということがこのテスト失敗で得られましたね。

投稿2021/02/14 08:04

winterboum

総合スコア23329

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cherry2020

2021/02/14 09:05

ありがとうございます。 winterboumさんのおかげでエラーの意味が分かりました。 development のDBと、test のDBは別物なんですね(;;) 試しに、development のDBをからにしたところ、テストコードと全く同じエラーが発生しました。 (1)ログイン後は、habitsではなく、イフゼンルールのページへ遷移させる (入力が必要ですと説明文を付け加えてhabitsページに行く前に登録してもらう) (2)入力・保存後は、habitsページに遷移させる (3)それに合わせたテストコードに書き直す を行ったところ、無事にパスしました!!!! 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問