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

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

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

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

Q&A

2回答

10228閲覧

rails SQLite3::ConstraintException: NOT NULL constraint failed: の原因と解決について

k-hayashi

総合スコア13

Ruby on Rails

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

0グッド

0クリップ

投稿2021/05/15 05:01

前提・実現したいこと

railsで宿泊予約サービスのシステムを作成しています。
予約内容を入力した後に、予約確定の画面に移るように「したいのですが、

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

ActiveRecord::NotNullViolation in ReservationsController#create SQLite3::ConstraintException: NOT NULL constraint failed: reservations.room_id Extracted source (around line #23): 21 @reservation = Reservation.new(reservation_params) 22 @reservation.user = current_user 23   if @reservation.save 24 flash[:notice] = "予約を完了しました" 25 redirect_to room_reservation_path(@room.id) 26 else

該当のソースコード

### resevations_conroller.rb class ReservationsController < ApplicationController before_action :set_search_header, only: [:index, :new, :posts, :show, :create] def index @users = User.all @reservations = Reservation.all end def show @user = User.find(params[:id]) @room = Room.find(params[:id]) end def new @room = Room.find(params[:room_id]) @reservation = Reservation.new end def create @reservation = Reservation.new(reservation_params) @reservation.user = current_user if @reservation.save flash[:notice] = "予約を完了しました" redirect_to room_reservation_path(@room.id) else render :new end end def update end private def set_search_header @search_header = User.ransack(params[:q]) if @search_header @users = @search_header.result(distinct: true) end end def reservation_params params.require(:reservation).permit(:user_id, :room_id, :start_date, :end_date, :number_of_people, :total_price) end end
### 予約入力画面(reservation/new.html.erb) <%= render "devise/shared/error", obj: @reservation %> <div class="raw"> <%= form_for @reservation do |f| %> <div class="d-flex"> <%= f.hidden_field :id, value: @reservation.id %> <div class="col-md-6"> <%= f.label :start_date, "開始日" %> <%= f.date_field :start_date, class: 'reservation-contents' %> </div> <div class="col-md-6"> <%= f.label :end_date, "終了日" %> <%= f.date_field :end_date, class: 'reservation-contents' %> </div> <div class="col-md-6"> <%= f.label :number_of_people, "人数" %> <%= f.number_field :number_of_people, class: 'reservation-contents' %> </div> <%= f.submit "予約する", class: 'form-control btn-primary mb-4' %> </div> <% end %> </div>
### 予約確定画面(reservation/show.html.erb) <%= render 'users/host' %> <%= form_for @reservation do |f| %> <div class="container-fiuld user"> <div class="row"> <div class="d-flex"> <div class="col-md-12 user-view"> <div class="user-view-box"> <% @reservation.each do |reservation| %> <div class="update-content"> <div class="row"> <div class="d-flex"> <%= f.label :room_name, '予約した部屋', class: 'col-md-3' %> <%= link_to room.room_name(room.id), room_path(room.id), class: "col-md-9" %> </div> </div> <div class="row"> <div class="d-flex"> <%= f.label :start_date, '開始日', class: 'col-md-3' %> <%= room.start_date(room.id), class: 'col-md-9' %> </div> </div> <div class="row"> <div class="d-flex"> <%= f.label :end_date ,'終了日', class: 'col-md-3' %> <%= room.end_date(room.id), class: 'col-md-9' %> </div> </div> <div class="row"> <div class="d-flex"> <%= f.label :total_price ,'価格', class: 'col-md-3' %> <%= room.price * room.number_of_people(room.id), class: 'col-md-9' %> </div> </div> </div> <% end %> </div> </div> </div> </div> </div> <div> <ul> <li><%= f.submit '登録完了する' %><li> <li><%= link_to "トップ画面に戻る", user_path(current_user.id) %></li> </ul> </div> <% end %>
### reservation.rb class Reservation < ApplicationRecord belongs_to :user, optional: true belongs_to :room, optional: true with_options presence: true do validates :start_date validates :end_date validates :number_of_people end validates_acceptance_of :confirming after_validation :check_confirming

試したこと

下記のサイトを参考にしましたが、解決に至りませんでした。
[https://teratail.com/questions/278865]
まだ始めたばかりで説明不足な点もあるかと思いますが、皆様の知恵を貸してください。よろしくお願いします。

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

エラーの内容の

ActiveRecord::NotNullViolation in ReservationsController#create SQLite3::ConstraintException: NOT NULL constraint failed: reservations.room_id

で翻訳を掛けると、
・NOT NULL制約があるカラム(入っていなきゃいけないカラム)であるreservations.room_idにデータが無いのでダメでした。
・ダメだったのは23行目です(save出来ませんでした)
と書いてあります。

とすると、reservations.room_idが送れていないのでsaveが出来ず、エラーになっているのかな?と推測できるので、
binding.pryが使えるようであれば、

def create binding.pry @reservation = Reservation.new(reservation_params) @reservation.user = current_user if @reservation.save flash[:notice] = "予約を完了しました" redirect_to room_reservation_path(@room.id) else render :new end end

と入れて確認してみると良いと思います。

結論の解決方法としては、hidden_fieldでreservations.room_idを送ってあげればいいかなと思います。

補足
①form_tagやform_forは非推奨になっていくかなと思うので、form_withを使っていくのをオススメします ( https://pikawaka.com/rails/form_with )
②roomとuserにoptional: trueを掛けているのはなぜでしょうか?これは外部キー(リレーションを掛けているuser_idやroom_id)が無くても保存できるようにするよ~というものです。
おそらく部屋の予約だとすると、どちらの外部キーも無いと困ると思うので、optional: trueは無くてもいいのかなと思いました(あくまで推測なので必要だったらごめんなさい)

色々回答してしまってすみませんm(_ _)m
私も未熟ですので違う所があるかもしれませんので公式等を参照して確認してみてください。

エラー処理や予約画面作るのは大変だと思いますが、頑張ってください!
長文失礼しました。

投稿2021/05/15 05:42

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

k-hayashi

2021/05/15 07:59

とても丁寧な回答ありがとうございます。エラーの解消にはなりませんでしたが、おかげさまでhidden_fieldの使い方を再確認できました。 optional; trueにしないとバリデーションのエラーメッセージでテーブル名が表示されてしまうため、使っております。optional: trueがあることによってこのエラーが出てしまうのであれば、これを使わずにbelongs_toで定義したテーブル名をバリデーションのエラーメッセージで表示させないようにできるのでしょうか?
退会済みユーザー

退会済みユーザー

2021/05/15 09:37

説明不足でごめんなさい、今回のエラーとoptional: trueは関係ないです。 予約入力画面(reservation/new.html.erb)に <%= f.hidden_field :room_id, value: room_id(ここはroom_idを示しているものを記述) %> を入れれば解決すると思います。 あくまで必要なのかな?と疑問に思ったので補足しました。 予約確定画面(reservation/show.html.erb)の記述も?と思う部分はあるので、複数修正しないといけないかもしれません >optional; trueにしないとバリデーションのエラーメッセージでテーブル名が表示されてしまうため、使っております。 とはどのような意味合いでしょうか?テーブル名が表示されるエラーとは何のエラーなのでしょう。私の理解が乏しくてごめんなさい、 もしかして私のバリデーションへの理解が違うのか、、、 ``` class Reservation < ApplicationRecord belongs_to :user, optional: true →reservationのid(例えばid: 1)はuser_idの1つとしか繋がらないよ、そしてuser_idはnilでもエラーにならないよ belongs_to :room, optional: true →reservationのid(例えばid: 1)はroom_idを1つとしか繋がらないよ、そしてroom_idはnilでもエラーにならないよ with_options presence: true do validates :start_date validates :end_date validates :number_of_people →これらは空白だとバリデーションがかかるよ end validates_acceptance_of :confirming →チェックがされていないとバリデーションかかるよ after_validation :check_confirming →バリデーションが掛かったらcheck_confirmingを実行してね ``` バリデーションの意味合いはこれで合っていますか?(不安なので少し確認です)
k-hayashi

2021/05/15 12:49

optional: true使わなかった場合、belongs_to :テーブル名のテーブル名、今回の場合はuserとroomがバリデーションのエラーメッセージとして表示されます。伝わりますか?すみません説明が下手で。。。というか今思ったんですけど、optional: true使わないとダメって言ってる時点で何かおかしい感じがしてきました。そもそも予約ボタン押す時にはuser_idとroom_idの値は格納されていないとおかしいですよね? >バリデーションの意味合いはこれで合っていますか?(不安なので少し確認です) 恐らくその解釈で間違いないと思います。自分の説明不足で違う解釈をさせてしまったかもしれません。 教えていただいたコードで試しましたが、解決せず、reservation/show.html.erbのコードも修正しましたが、結局idが取得できずでした。 もう少し調べながら解決したいと思います。 お付きあいいただきありがとうございます。
退会済みユーザー

退会済みユーザー

2021/05/15 13:27

>というか今思ったんですけど、optional: true使わないとダメって言ってる時点で何かおかしい感じがしてきました。そもそも予約ボタン押す時にはuser_idとroom_idの値は格納されていないとおかしいですよね? 全てを確認していないので一概にそうだとは言えません。 でも、それに気づく感覚めちゃくちゃ大事ですよ~良きです(*'▽') 良くコードを見返したところ、宿とかを選択する(new画面)→予約したものを確認する(confirm画面)→予約完了(show画面)! というルートを踏まなければいけないのに、宿を選択するの時点でcreate(情報をDBに保存)しているので、そこから違うかもしれません。 confirm画面の作成とsession[:id]かhidden_fieldで情報を渡していく方法を調べることをオススメします。ECサイトの予約確認画面とかが参考になるかなと思います。 もし、まだそのレベルまで行っていなくて、何言っているか全然分かんないとかであれば予約確認画面を作らずに完了のルートで作ってしまうのもいいかなと思います。 適当にやると動いてくれなくなるので細かくどういう意味か確認しながらやると理解もしやすいと思います!頑張ってください!
guest

0

SQLite3::ConstraintException: NOT NULL constraint failed: reservations.room_idはその名の通り、NULLを許容していないカラムにNULLが指定されてINSERTまたはUPDATE文が発行された事による例外です。
この場合、reservations.room_idがNULL(Rubyではnil)である事が原因でしょう。

reservation_paramsにroom_idが含まれている必要があります。

投稿2021/05/15 05:32

mingos

総合スコア4025

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問