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

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

詳細はこちら
Ruby on Rails 6

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

Q&A

解決済

1回答

1144閲覧

[saveエラー]ActiveRecord::NotNullViolation in CommentsController#create

YutoKubo

総合スコア13

Ruby on Rails 6

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

0グッド

0クリップ

投稿2021/02/12 09:27

コメント機能を作成中にフォームから投稿したコメントが表示されない不具合があり、if @comment.saveにbinding.pryを
かけてみましたが反応せず、保存処理がなされていませんでした。
そこで、save!としてエラーメッセージを出力すると
[エラー文]Validation failed: "モデル" must exist となり、エラー文を検索すると
参考記事:https://qiita.com/tanaka7014/items/50a1a953b3f440cbe481とあったので
comment.rbのbelongs_toに'optional: true'を追加しました。
すると以下のようなエラー文に遭いました。データの保存に失敗していることは分かるのですが
それ以上エラー文を解釈できず、お力添えを頂ければと思います。

ActiveRecord::NotNullViolation in CommentsController#create SQLite3::ConstraintException: NOT NULL constraint failed: comments.community_id Extracted source  __if @comment.save!__(エラー箇所) flash[:success] = "コメントしました" redirect_back(fallback_location: root_path) else

<comments_controller.rb>

class CommentsController < ApplicationController def create @comment = Comment.new(comment_params) @comment.user_id = current_user.id #上の2行だけではコメントをしたユーザーの関連付けをできないため書いています(コメントは誰のものなのか) if @comment.save! flash[:success] = "コメントしました" redirect_back(fallback_location: root_path) else flash[:success] = "コメントできませんでした" redirect_back(fallback_location: root_path) end end private def comment_params params.require(:comment).permit(:content) end end

<communities_controller.rb>

lass CommunitiesController < ApplicationController before_action :set_community, only: [:edit,:show,:update] def index @communities = Community.all end def show @comments = @community.comments #投稿詳細に関連付けてあるコメントを全取得 @comment = Comment.new #投稿詳細画面でコメントの投稿を行うので、formのパラメータ用にCommentオブジェクトを取得 end def edit @community = Community.find(params[:id]) end def new @community = Community.new end def create @community = current_user.communities.build(community_params) if @community.save redirect_to community_path(@community), notice: "投稿に成功しました。" else render :new end end def update if @community.update(community_params) redirect_to community_path, notice: "投稿を更新しました。" else render :edit end end def destroy community = Community.find(params[:id]) community.destroy redirect_to communities_path, notice: "投稿を削除しました。" end private def community_params params.require(:community).permit(:title, :body, :image, :content) end def set_community @community = Community.find(params[:id]) end end

<comment.rb>

class Comment < ApplicationRecord belongs_to :user belongs_to :community # validates :content, presence: true, length: { maximum: 140 } end

<log>(コメント入力欄に”こんにちは”と入力)

Started POST "/communities/1/comments" for ::1 at 2021-02-12 18:18:15 +0900 (0.1ms) SELECT sqlite_version(*) Processing by CommentsController#create as HTML Parameters: {"authenticity_token"=>"OKAibpz00Oo96iCmc9a94tl22sqsMB1W9sLRkMYKDUiJzSSGgo6NTQfjJh19ZM/S6XBnlxe+KSB3Wkeb7kw2Yg==", "comment"=>{"content"=>"こんにちは"}, "commit"=>"コメントする", "community_id"=>"1"} User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/comments_controller.rb:4:in `create' (0.1ms) begin transaction ↳ app/controllers/comments_controller.rb:7:in `create' User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/comments_controller.rb:7:in `create' (0.1ms) rollback transaction ↳ app/controllers/comments_controller.rb:7:in `create' Completed 422 Unprocessable Entity in 27ms (ActiveRecord: 1.4ms | Allocations: 21086)

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんばんは。
エラーメッセージがちゃんと教えてくれているので、それを頼りに書いてみますね。

SQLite3::ConstraintException: NOT NULL constraint failed: comments.community_id

とあるので、Commentsテーブルのcommunity_idはnullではいけなさそうですね。
(belongs_toも設定されているので commentとcommunityは関連付けが要る)

リクエストパラメータからcommunity_idを正しく渡せてないのでは?
comment_paramsに入っているのは、contentだけなので。

ruby

1 2 # デバッグすると、comment_paramsには、comment_id が入っていないはず 3 @comment = Comment.new(comment_params) 4 @comment.user_id = current_user.id 5 6 # たぶんsaveの前に、このへんが必要なのかなと。 7 # 20210213 ここを修正しました params(:comment_id) でなく params[:comment_id] 8 @comment.community_id = params[:comment_id] 9

20210213 追記:

コメントで params(:comment_id) としたらエラーになってしまったとのことで、失礼いたしました!
もとのままだと メソッドとして認識するので、arguments (given 1, expected 0) になってしまいます。すみません...。

ハッシュから値を取り出すことになるので、正しくは以下になります。

@comment.community_id = params[:comment_id]

ですね。

また、この値はどこから来ているのかですが、リクエストパラメータからです。
コントローラーに対するログに、以下のように「こういうパラメータでリクエストを送ってますよ」という情報が書き出されています。

ruby

1Processing by CommentsController#create as HTML 2 Parameters: {"authenticity_token"=>"OKAibpz00Oo96iCmc9a94tl22sqsMB1W9sLRkMYKDUiJzSSGgo6NTQfjJh19ZM/S6XBnlxe+KSB3Wkeb7kw2Yg==", "comment"=>{"content"=>"こんにちは"}, "commit"=>"コメントする", "community_id"=>"1"}

comment_paramsを処理しているので、このあたりのことはご周知かと思いますが、コントローラ側に渡った時には、params という変数に、このデータ一式が入ります。
たまに悪意を持って変なデータを送りつけてくるものもあるので、このparamsから、必要な値だけを取り出したり、バリデーションしたものを使って保存する...という流れになりますね。

ruby

1 2# さて、コントローラの中でデバッグすると、paramsの中身は... 3params 4 5# この情報が入っています 6{"authenticity_token"=>"OKAibpz00Oo96iCmc9a94tl22sqsMB1W9sLRkMYKDUiJzSSGgo6NTQfjJh19ZM/S6XBnlxe+KSB3Wkeb7kw2Yg==", "comment"=>{"content"=>"こんにちは"}, "commit"=>"コメントする", "community_id"=>"1"} 7 8# comment_paramsは、このparamsの中の、params[:comment][:content]の値が入っているけれど、 9# comment_id は、params[:comment_id] としないと取り出せないです

如何でしょうか。
うまくいきますように。

投稿2021/02/12 11:16

編集2021/02/12 22:35
suama

総合スコア1997

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

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

YutoKubo

2021/02/12 14:10

community_idがsaveの前に@commentに渡せていないことがエラー原因なのは理解できたのですが、 @comment.community_id = params(:comment_id)のコードの意味を教えて頂けないでしょうか? また、こちらのコードをsaveの前に追加したところwrong number of arguments (given 1, expected 0) と引数エラーになりました。
suama

2021/02/12 22:23

おはようございます! 手元で動かせてないのですが、まず1つめ。 params(:comment_id) じゃなくて、params[:comment_id] でした。大変失礼いたしました。([ ] のほうです。回答側にも修正添えておきます!) 回答に追記しますので、お待ちくださいませ。
YutoKubo

2021/02/13 06:03 編集

なるほど。ありがとうございます。しかし依然と同じエラーのままで。見当違いかもしれないのですが、 @commentのcommunity_idの"nill"はoptional: trueで許容されるはずなのですが,以下のためnullとなってしまっているせいでエラーになっているのかと考えました。 うまく言語化できないですが、パラメータのcomment=>{ } の中に"community_id"=>"1"が入っている必要があるのではないでしょうか? Parameters: {"authenticity_token"=>"OKAibpz00Oo96iCmc9a94tl22sqsMB1W9sLRkMYKDUiJzSSGgo6NTQfjJh19ZM/S6XBnlxe+KSB3Wkeb7kw2Yg==", "comment"=>{"content"=>"こんにちは"}, "commit"=>"コメントする", "community_id"=>"1"}
YutoKubo

2021/02/13 06:05 編集

comment:=>{ content: ***, community_id: *** }} このようになっている必要があると他のアンサーの方にもご指摘をうけました。 ただコードをどう修正すればいいのかわからず...。
suama

2021/02/13 06:26

まずは @comment.community_id = 1 とハードコードして、登録が正しくできるか確認してみては? あまり引っ張るのも申し訳ないのですが、プログラムは書かれたとおりに動きます。 期待するパラメータになるようにしたければ、HTML側(html.erb)を直しましょう。
YutoKubo

2021/02/13 06:54

ん〜、@comment.community_id = 1 はちゃんとできました。
suama

2021/02/13 08:50

他の方の回答も拝見しました。 期待するパラメータになるようにしたければ、HTML側(html.erb)を直しましょう。 が、最後の答えになります。
YutoKubo

2021/02/15 10:01

[:追記]community_idを取得し@commentとcommunity_idの関連付けをします。 if @comment.save!の前に@comment.community_id = params[:community_id] をすることで解決しました。 また、userとcommentがアソシエーションで繋がっているため、 @comment = Comment.new(comment_params) @comment.user_id = current_user.id        この二行は @comment = current_user.comments.new(comment_params)と書くことができます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問