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

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

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

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

RSpec

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

Ruby on Rails

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

Q&A

解決済

2回答

1015閲覧

Rspec validateの中でparameterを使用しているときのモデルspecについて

IRIESS

総合スコア45

Ruby

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

RSpec

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

Ruby on Rails

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

0グッド

0クリップ

投稿2021/11/28 12:48

編集2021/11/29 07:16

Rails APIを使用してアプリを作成しています。

現在下記のようなagreementモデルがあります。
roomで話し合い、userとhostが合意したらagreementを作成できます。
agreementのupdate機能を追加した際に、自分自身に対しても時間帯(start_timeとfinish_time)の重複チェックをしてしまうため、room_idからroomを特定しroom.agreementがnilでない場合にroom.agreement.idを重複チェックの要素に入れ、自分自身を除いた重複チェックができるようにしました。

しかしモデルspecでテストを実行した際に、room = Room.find(room_id)の部分でidがないと怒られました。

パラメータを渡してないからだと思うのですが、ではどのようにしてモデルテストを記述したら良いのか分かりません。。。。。
リクエストspecに書き換えたほうがいいでしょうか?
ベストプラクティスをご教授お願い致します。

ruby

1# agreement.rb 2 3 belongs_to :user 4 belongs_to :host 5 belongs_to :room 6validate :duplication_of_work_hours_for_same_user 7 8def duplication_of_work_hours_for_same_user 9 room = Room.find(room_id) 10 if room.agreement.nil? 11 Agreement.where('finish_time >= ? && ? >= start_time && user_id = ?', start_time, finish_time, user_id).exists? 12 errors.add(:start_time, "userの勤務期間が他の契約と重複していますneeee。") 13 else 14 agreement = room.agreement 15 if Agreement.where('id != ? && finish_time >= ? && ? >= start_time && user_id = ?', agreement.id, start_time, finish_time, user_id).exists? 16 errors.add(:start_time, "userの勤務期間が他の契約と重複しています。") 17 end 18 end 19 end

ruby

18) Agreement start_time, finish_time 1時間なら有効 2 Failure/Error: room = Room.find(room_id) 3 4 ActiveRecord::RecordNotFound: 5 Couldn't find Room without an ID 6 # ./app/models/agreement.rb:33:in `duplication_of_work_hours_for_same_user' 7 # ./spec/models/agreement_spec.rb:58:in `block (3 levels) in <top (required)>'

ruby

1it "1時間ちょうどなら有効" do 2 agreement = build(:agreement, finish_time: Time.current + 25.hour) 3 expect(agreement).to be_valid 4 end

ruby

1FactoryBot.define do 2 factory :agreement do 3 association :user 4 association :host 5 association :room 6 start_time { Time.current + 24.hour } 7 finish_time { Time.current + 32.hour } 8 state { 0 } 9 end 10end

ruby

1 2# 3このコードで解決しました。 4it "ちょうど1時間なら有効" do 5 agreement = build(:agreement, room: room, user: room.user, host: room.host, finish_time: Time.current + 25.hour) 6 expect(agreement).to be_valid 7 end

そして

ruby

1if room.agreement.nil? 2 Agreement.where('finish_time >= ? && ? >= start_time && user_id = ?', start_time, finish_time, user_id).exists? 3 errors.add(:start_time, "userの勤務期間が他の契約と重複していますneeee。") 4 else 5 6ここにifをつけ忘れていたこともややこしくしていました泣泣 7正しくは 8 9if room.agreement.nil? 10 if Agreement.where('finish_time >= ? && ? >= start_time && user_id = ?', start_time, finish_time, user_id).exists? 11 errors.add(:start_time, "userの勤務期間が他の契約と重複していますneeee。") 12 end 13 else 14 15に修正しました

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

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

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

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

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

guest

回答2

0

おそらく、build した agreement の room が保存されていません。
FactoryBot でbuildしたとき、関連先がcreateされなくなっていた(デフォルトの挙動として)

記事の通りにするか、strategy に create を指定する、または以下のようにしてみてください。

ruby

1agreement = build(:agreement, finish_time: Time.current + 25.hour) 2agreement.room.save 3 4expect(agreement).to be_valid

投稿2021/11/28 22:34

neko_daisuki

総合スコア2090

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

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

IRIESS

2021/11/29 06:15

回答ありがとうございます! 指定の通りにテストを記述してみたら、room_idがやはり渡されませんでした。今回は実装ではroomは先に存在した上でagreementが作られる実装にしているので、先にroomを作るようにテストを記述したところ、テストが通るようになりました。解決したテストを追記しました。 ご回答ありがとうございました!
guest

0

ベストアンサー

パラメータを渡してないからだと思うのですが

いえ、パラメーターの問題ではありません。エラーメッセージのとおり、このモデルへroom_idをセットしない場合、本当に例外を発生させてしまいます

room_idがない場合はどのような動作をさせたいかを考えて、それに合わせた実装・テストを書く必要があります。

投稿2021/11/28 22:28

maisumakun

総合スコア146018

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

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

maisumakun

2021/11/28 22:31

roomとagreementを同時作成しようとした場合には、「roomからは取れるけど、DBには未保存なのでroom_idはnil」となることが考えられます。このような場合まで考えるなら、room_idからRoomを取ること自体が妥当ではないかもしれません。
IRIESS

2021/11/29 06:07

なるほど、ファクトリーボッドのアソシエーション任せにすると、roomとagreementが同時作成されるからroom_idはnilになってしまうということですか。 実際にagreementが作成される場合にはroomから作るため必ずroomは存在するので、実装は変えずに、テストを追記のような形で記入することでとりあえず解決できました。テストは長くなってしまいましたが。 今回もご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問