🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
DELETE

ファイルシステムからファイル、データベースからレコードを削除することまたはメモリ内のオブジェクトの割り当てを取り消すことをさします。もしくは、HTTPプロトコルのDELETEを指すこともあります。

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

RSpec

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

Q&A

解決済

2回答

3011閲覧

Rspecを使ってコントローラのdeleteのテストをしていますが、エラーが出るのを解消したい

a-ichi

総合スコア16

DELETE

ファイルシステムからファイル、データベースからレコードを削除することまたはメモリ内のオブジェクトの割り当てを取り消すことをさします。もしくは、HTTPプロトコルのDELETEを指すこともあります。

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

RSpec

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

0グッド

0クリップ

投稿2021/01/01 09:03

初学者です。
オリジナルアプリで、初めてコントローラーのテストをしています。
いろんな方の記事を見てテストを記載していますが、解決方法が分からない部分が出てきましたので質問させて頂きました。
記載方法が間違っている部分が多いと思いますが、何卒宜しくお願い致します。

解決したいこと
Rspec を使ってコントローラのdeleteのテストをしていますが、ActiveRecord::InvalidForeignKey:のエラーと
No route matchesのエラーが出るのを解消したいです。

環境
ruby 2.6.5
rails 6.0.0
gem 'rspec-rails', '~> 4.0.0.beta3'
gem 'rails-controller-testing'
gem "devise"

エラーコード
ターミナル

Failure/Error: @event = FactoryBot.create(:event) ActiveRecord::InvalidForeignKey: Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails (`rc_app2_test`.`events`, CONSTRAINT `fk_rails_0cb5590091` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`))  Failure/Error: delete :destroy ActionController::UrlGenerationError: No route matches {:action=>"destroy", :controller=>"events"}

events_controller_spec.rbの該当箇所

ruby

1require 'rails_helper' 2 3describe EventsController, type: :controller do 4 5 describe '#destroy' , type: :controller do 6 7 context 'log in' do 8 context 'can destroy' do 9 10 it 'deletes a event' do 11 sign_in @user 12      @event = FactoryBot.create(:event) 13 expect{ delete :destroy, params: {id: @event.id} 14 }.to change(@user.events, :count).by(-1) 15 end 16 17 it 'redirects to root_path' do 18 19 sign_in @user 20 expect(response).to redirect_to(root_path) 21 end 22 end 23 24 context 'not log in' do 25 it "redirects to new_user_session_path" do 26 delete :destroy 27 expect(response).to redirect_to(new_user_session_path) 28 end 29 end 30 end 31 end 32end

routes

ruby

1Rails.application.routes.draw do 2 devise_for :users 3 root to: "events#index" 4 resources :events 5 resources :customers 6 # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 7end 8

factorybot event.rb

ruby

1FactoryBot.define do 2 3 factory :event do 4 title {"タイトル"} 5 start_time {"2020/11/11/10:00"} 6 end_time{"2020/11/11/10:00"} 7 user_id{"1"} 8 9 10 end 11end

factorybot user.rb

ruby

1FactoryBot.define do 2 3 factory :user do 4 email {"kkk@gmail.com"} 5 password {"00000000"} 6 password_confirmation {"00000000"} 7 8 end 9 10end

spec/rails_helper.rb

ruby

1# This file is copied to spec/ when you run 'rails generate rspec:install' 2require 'spec_helper' 3ENV['RAILS_ENV'] ||= 'test' 4require File.expand_path('../config/environment', __dir__) 5# Prevent database truncation if the environment is production 6abort("The Rails environment is running in production mode!") if Rails.env.production? 7require 'rspec/rails' 8# Add additional requires below this line. Rails is not loaded until this point! 9 10# Requires supporting ruby files with custom matchers and macros, etc, in 11# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 12# run as spec files by default. This means that files in spec/support that end 13# in _spec.rb will both be required and run as specs, causing the specs to be 14# run twice. It is recommended that you do not name files matching this glob to 15# end with _spec.rb. You can configure this pattern with the --pattern 16# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 17# 18# The following line is provided for convenience purposes. It has the downside 19# of increasing the boot-up time by auto-requiring all files in the support 20# directory. Alternatively, in the individual `*_spec.rb` files, manually 21# require only the support files necessary. 22# 23Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } 24 25# Checks for pending migrations and applies them before tests are run. 26# If you are not using ActiveRecord, you can remove these lines. 27begin 28 ActiveRecord::Migration.maintain_test_schema! 29rescue ActiveRecord::PendingMigrationError => e 30 puts e.to_s.strip 31 exit 1 32end 33RSpec.configure do |config| 34 # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 35 config.fixture_path = "#{::Rails.root}/spec/fixtures" 36 config.include FactoryBot::Syntax::Methods 37 Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 38 config.include Devise::Test::ControllerHelpers, type: :controller 39 config.include ControllerMacros, type: :controller 40 # If you're not using ActiveRecord, or you'd prefer not to run each of your 41 # examples within a transaction, remove the following line or assign false 42 # instead of true. 43 config.use_transactional_fixtures = true 44 45 # You can uncomment this line to turn off ActiveRecord support entirely. 46 # config.use_active_record = false 47 48 # RSpec Rails can automatically mix in different behaviours to your tests 49 # based on their file location, for example enabling you to call `get` and 50 # `post` in specs under `spec/controllers`. 51 # 52 # You can disable this behaviour by removing the line below, and instead 53 # explicitly tag your specs with their type, e.g.: 54 # 55 # RSpec.describe UsersController, type: :controller do 56 # # ... 57 # end 58 # 59 # The different available types are documented in the features, such as in 60 # https://relishapp.com/rspec/rspec-rails/docs 61 config.infer_spec_type_from_file_location! 62 63 # Filter lines from Rails gems in backtraces. 64 config.filter_rails_from_backtrace! 65 # arbitrary gems may also be filtered via: 66 # config.filter_gems_from_backtrace("gem name") 67end 68

event_controller.rb

ruby

1 before_action :set_event, only: [:show, :edit, :update, :destroy] 2 before_action :move_to_index,except:[:index] 3 4 def destroy 5 if @event.destroy 6 redirect_to root_path, notice: 'イベントを削除しました' 7 else 8 flash.now[:alert] = 'イベントを削除できませんでした' 9 render :show 10 end 11 end 12 13 private 14 15 def set_event 16 @event = Event.find(params[:id]) 17 end 18 def move_to_index 19 unless user_signed_in? 20 redirect_to action: :index 21 end 22 end

他のindexアクションとshowアクションはうまくいきました。
destroyアクションでつまづいています。
↓うまく行った部分。events_controller_spec.rb

ruby

1describe EventsController, type: :controller do 2 before do 3 @user = FactoryBot.create(:user) 4 end 5 6 describe 'GET #index' do 7 it "renders the :index template" do 8 get :index 9 expect(response).to render_template :index 10 end 11 it "returns a 200 response" do 12 get :index 13 expect(response).to have_http_status "200" 14 end 15 end 16 17 describe 'GET #new' , type: :controller do 18 19 context 'log in' do 20 it "renders the :new template" do 21 sign_in @user 22 get :new 23 expect(response).to render_template :new 24 end 25 end 26 context 'not log in' do 27 it "redirects to new_user_session_path" do 28 get :new 29 expect(response).to redirect_to(new_user_session_path) 30 end 31 end 32 end 33 34 describe '#create' , type: :controller do 35 let(:params) { { title: "タイトル" , event: attributes_for(:event) } } 36 37 context 'log in' do 38 context 'can save' do 39 subject { 40 post :create, 41 params: params 42 } 43 it 'count up event' do 44 sign_in @user 45 expect{ subject }.to change(Event, :count).by(1) 46 end 47 48 it 'redirects to root_path' do 49 sign_in @user 50 subject 51 expect(response).to redirect_to(root_path) 52 end 53 end 54 context 'can not save' do 55 let(:invalid_params) { { event: attributes_for(:event, title: nil) } } 56 57 subject { 58 post :create, 59 params: invalid_params 60 } 61 62 it 'does not count up' do 63 sign_in @user 64 expect{ subject }.not_to change(Event, :count) 65 end 66 67 it 'renders index' do 68 sign_in @user 69 subject 70 expect(response).to redirect_to(new_event_path) 71 end 72 end 73 context 'not log in' do 74 it "redirects to new_user_session_path" do 75 post :create 76 expect(response).to redirect_to(new_user_session_path) 77 end 78 end 79 end 80 end 81

ご回答宜しくお願い致します。

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

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

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

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

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

guest

回答2

0

ベストアンサー

botでemail {"kkk@gmail.com"}と固定のemailを使っています。
testは通常は終わるたびにDBを戻すことになっていますが、何かのタイミングで削除されないうちに次のテストのbeforeが走ったのだろうと思われます。
emailを乱数的につくるか、Faker 使うかしてみてください

投稿2021/01/10 09:55

winterboum

総合スコア23567

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

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

a-ichi

2021/01/11 10:23

winterboum様 ありがとうございます。 Faker使ってみます。
guest

0

問題となっているのは

user_id{"1"}

ここです。
userid="1"で作られていない場合、これでは無効になってしまいます。

というわけで、associationを使います。

今回は、factory name association nameが同一になるので

ruby

1FactoryBot.define do 2 3 factory :event do 4 title {"タイトル"} 5 start_time {"2020/11/11/10:00"} 6 end_time {"2020/11/11/10:00"} 7 user 8 end 9end

で大丈夫なはずです。

他の書き方としては

ruby

1user factory: :user 2association :user, factory: :user 3user {association :user}

など様々な書き方があります。

投稿2021/01/01 22:48

asm

総合スコア15149

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

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

a-ichi

2021/01/02 02:34

asm様 ご回答ありがとうございます。 上記の件、試すとidが無いエラーは解消されました。 ありがとうございます。 ただ、変わりに 1) EventsController#destroy log in can destroy deletes a event Failure/Error: @event = FactoryBot.create(:event) ActiveRecord::RecordInvalid: バリデーションに失敗しました: Eメールはすでに存在します のエラーが出てしまいました。 before do @user = FactoryBot.create(:user) end でログインしているからeメールのバリデーション がかかってしまったのでしょうか? また、 2) EventsController#destroy log in can destroy redirects to root_path Failure/Error: delete :destroy ActionController::UrlGenerationError: No route matches {:action=>"destroy", :controller=>"events"} こちらのエラーの解消方法は分かりますでしょうか?
asm

2021/01/02 05:06 編集

> 1) バリデーションに失敗しました: Eメールはすでに存在します なんらかの理由ですでにtest用データベースに同emailを利用しているuserがあるようです $ rails db:test:prepare コマンドでtest用データベースを再構築できるかもしれません。 > 2) EventsController#destroy log in can destroy redirects to root_path Deviseのsign_inヘルパーはログイン"状態"にするのであってログインリクエストを発行するのとは違います。 よってログインした時のリダイレクト先をこの方法でテストする事はできません。 また、EventsControllerのテストでやることなのかも疑問です。
a-ichi

2021/01/02 06:14

asm様 > 1) バリデーションに失敗しました: Eメールはすでに存在します $ rails db:test:prepareコマンドを入力してみましたが、 warning ../package.json: No license field のエラーでした。 package.jsonに"license": "UNLICENSED"を入力し、yarn installをしましたが、warning ../package.json: No license fieldのエラーは変わらずでした。 シークエルプロを確認しましたが、testの中には何も記載がありませんでした。 何か他に理由があるのでしょうか? > 2) EventsController#destroy log in can destroy redirects to root_path こちらはEventsControllerのテストでやるべき事では無いのですね。こちらは諦めます。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問