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

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

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

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

RSpec

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

Q&A

解決済

1回答

2227閲覧

Everyday Rails Rspec テストエラー「NoMethodError undefined method 'owner' for nil:NilClass」の原因が分からない

natecosan

総合スコア23

Ruby on Rails 5

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

RSpec

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

0グッド

0クリップ

投稿2019/07/16 07:17

編集2019/07/16 07:27

前提・実現したいこと

『Everyday Rails RSpecによるRailsテスト入門』の7章を学習しています。
演習問題で、サンプルアプリケーションに別のAPIエンドポイントを追加してテストも書いてみましょうというものがあるので、それを進めていたところ、テストが通らず原因が分からないため相談させてください。

テキストのサンプルとなっていた「ProjectApi」を参考に、Projectに紐づいたNoteのAPIを作成しました。
APIでノートを読み込むのは成功するのですが、
投稿しようとするとnoteが紐づいているprojectがnilになっている?とのエラーが出てしまいます。
どこを修正したらよいかわからず…よろしくお願いします!

発生している問題・エラーメッセージ

console

1$ bin/rspec spec/requests 2Running via Spring preloader in process 27368 3 4Home page 5 responds successfully 6 7NotesApi 8 loads a note 9 creates a note (FAILED - 1) 10 11ProjectsApi 12 loads a project 13 creates a project 14 15Projects 16 as an authenticated user 17 with valid attributes 18 adds a project 19 with invalid attributes 20 does not add a project 21 22Failures: 23 24 1) NotesApi creates a note 25 Failure/Error: user { project.owner } 26 27 NoMethodError: 28 undefined method `owner' for nil:NilClass 29 # ./spec/factories/notes.rb:5:in `block (3 levels) in <top (required)>' 30 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute/dynamic.rb:16:in `instance_exec' 31 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute/dynamic.rb:16:in `block in to_proc' 32 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/evaluator.rb:77:in `instance_exec' 33 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/evaluator.rb:77:in `block in define_attribute' 34 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute_assigner.rb:56:in `get' 35 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute_assigner.rb:26:in `block in hash' 36 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute_assigner.rb:25:in `each' 37 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute_assigner.rb:25:in `inject' 38 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/attribute_assigner.rb:25:in `hash' 39 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/strategy/attributes_for.rb:9:in `resul # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/strategy/attributes_for.rb:9:in `result' 40 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/factory.rb:43:in `run' 41 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/factory_runner.rb:29:in `block in run' 42 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/factory_runner.rb:28:in `run' 43 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/factory_bot-4.10.0/lib/factory_bot/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method' 44 # ./spec/requests/notes_api_spec.rb:42:in `block (2 levels) in <top (required)>' 45 # /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call' 46 # -e:1:in `<main>' 47 48Finished in 0.7658 seconds (files took 0.27768 seconds to load) 497 examples, 1 failure 50 51Failed examples: 52 53rspec ./spec/requests/notes_api_spec.rb:37 # NotesApi creates a note

該当のソースコード

  • note_api_spec.rb

ruby

1require 'rails_helper' 2 3describe "NotesApi", type: :request do 4 #1件のノートを読み出すこと 5 it 'loads a note' do 6 user = FactoryBot.create(:user) 7 8 project = FactoryBot.create(:project, 9 name: "Sample Project", 10 owner: user) 11 12 FactoryBot.create(:note, 13 message: "Sample Note", 14 project: project) 15 16 get api_project_notes_path(project.id), params: { 17 user_email: user.email, 18 user_token: user.authentication_token, 19 } 20 21 expect(response).to have_http_status(:success) 22 json = JSON.parse(response.body) 23 expect(json.length).to eq 1 24 note_id = json[0]["id"] 25 26 get api_project_note_path(id:1), params: { 27 user_email: user.email, 28 user_token: user.authentication_token 29 } 30 31 expect(response).to have_http_status(:success) 32 json = JSON.parse(response.body) 33 expect(json["message"]).to eq "Sample Note" 34 end 35 36 #ノートを作成できること 37 it 'creates a note' do 38 user = FactoryBot.create(:user) 39 project = FactoryBot.create(:project, 40 name: "Sample Project", 41 owner: user) 42 note_attributes = FactoryBot.attributes_for(:note) 43 44 expect{ 45 post api_project_notes_path(project.id), params:{ 46 user_email: user.email, 47 user_token: user.authentication_token, 48 project: project, 49 note: note_attributes 50 } 51 }.to change(project.notes, :count).by(1) 52 53 expect(response).to have_http_status(:success) 54 end 55end
  • notes_controller.rb (noteAPIのコントローラー)

ruby

1module Api 2 class NotesController < ApplicationController 3 prepend_before_action :authenticate_user_from_token! 4 5 def index 6 @project = Project.find(params[:project_id]) 7 @notes = @project.notes 8 render json: @notes 9 end 10 11 def show 12 @note = Note.find(params[:id]) 13 render json: @note 14 end 15 16 def create 17 @project = Project.find(params[:project_id]) 18 @note = @project.new(note_params) 19 20 if @note.save 21 render json: { status: :created } 22 else 23 render json: @project.errors, status: :unprocessable_entity 24 end 25 end 26 27 private 28 29 def authenticate_user_from_token! 30 user_email = params[:user_email].presence 31 user = user_email && User.find_by(email: user_email) 32 if user && Devise.secure_compare(user.authentication_token, params[:user_token]) 33 sign_in user, store: true 34 else 35 render json: { status: "auth failed" } 36 false 37 end 38 end 39 40 def note_params 41 params.require(:note).permit(:message) 42 end 43 end 44end
  • note.rb (noteのファクトリー)

ruby

1FactoryBot.define do 2 factory :note do 3 message "My important note." 4 association :project 5 user { project.owner } 6 end 7end
  • project.rb (projectのファクトリー)

Ruby

1FactoryBot.define do 2 factory :project do 3 sequence(:name) { |n| "Project #{n}" } 4 description "A test project." 5 due_on 1.week.from_now 6 association :owner 7 8 #メモ付きのプロジェクト 9 trait :with_notes do 10 after(:create) { |project| create_list(:note, 5, project: project)} 11 end 12 13 #昨日が締め切りのプロジェクト 14 trait :due_yesterday do 15 due_on 1.day.ago 16 end 17 18 #今日が締め切りのプロジェクト 19 trait :due_today do 20 due_on Date.current.in_time_zone 21 end 22 23 #明日が締め切りのプロジェクト 24 trait :due_tomorrow do 25 due_on 1.day.from_now 26 end 27 28 #無効のプロジェクト 29 trait :invalid do 30 name nil 31 end 32 33 end 34end
  • user.rb (userのファクトリー)

ruby

1FactoryBot.define do 2 factory :user, aliases: [:owner] do 3 first_name "Aaron" 4 last_name "Sumner" 5 sequence(:email) { |n| "tester#{n}@example.com" } 6 password "dottle-noubeau-pavilion-tights-furze" 7 8 trait :with_projects do 9 after(:create) { |user| create_list(:project, 5, owner: user) } 10 end 11 end 12end

考えたこと

@をつけなければいけない箇所があるとかでしょうか。。。

補足情報(FW/ツールのバージョンなど)

実行環境

AWS Cloud9
Ruby 2.6.3
Rails 5.1.1
RSpec 3.6
Chrome 75

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

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

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

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

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

guest

回答1

0

ベストアンサー

user { project.owner }
このタイミングで project がまだできていないからです。

before(:create) で作って下さい

投稿2019/07/24 13:32

winterboum

総合スコア23376

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

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

natecosan

2019/07/25 06:01

なるほど!!ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問