🦊

【Ruby on Rails】ParameterMissingのエラーでは、インスタンス変数を定義している場所も確認してみる

2024/07/02に公開

2024/1からプログラミングスクールに通っている、プログラミング初学者です。
2024/6/28より自分自身のアウトプットのために、毎日投稿をしています。
初学者の投稿になるため間違い等ございましたら、優しくご指摘いただけますと幸いです。

ParameterMissing (param is missing or the value is empty: comment)のエラー解消法

こちらのエラー解消に少し時間を要したので、今回は備忘録のためにも残しておこうと思います。

結論

今回のエラーは、インスタンス変数を定義しているコントローラー、およびアクションが違ったためにエラーが出ておりました。
中々ParameterMissing (param is missing or the value is empty: comment)のエラーが解消できない方は、私と同じようにインスタンス変数の定義場所が相違しているために、エラー解消できない可能性もあるのではと思い、記事を書いております。
参考になりましたら、幸いです。

エラー発生状況

  • Rails7.1.3.4

  • 記事の詳細画面内(app/views/articles/show.html.erb)で、コメント入力画面を表示したい
    -> app/views/comments/_form.html.erbでコメント入力欄のパーシャルファイルを作成。
    app/views/articles/show.html.erbの中で、<%= render 'comments/form', comment: @comment, article: @article %>という形で表示。
    => ここのファイル構造をちゃんと理解していれば、エラー解消まで時間がかからなかったはず...

  • articleとcommentは、1対多の関係

  • userとcommentも1対多の関係

エラーが発生した時のコード状況

  • routes.rb
  • articlesルーティングに、ネストした形でcommentsルーティングを設定
resources :articles do
  resources :comments, shallow: true
end
  • app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def new
  @comment = Comment.new
end

def create
  @comment = current_user.comments.build(comment_params)
  @comment.save
  redirect_to article_path(@comment.article_id)
end

- 省略 - 

private

def comment_params
  params.require(:comment).permit(:body).merge(article_id: params[:article_id])
end
end
  • app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :set_article, only: [:edit, :update, :destroy]

  def index
    @q = Article.ransack(params[:q])
    @articles = @q.result(distinct: true).includes(:user).order(created_at: :desc)
  end

  def new
    @article = Article.new
  end

  def create
    @article = current_user.articles.build(article_params)

    if @article.save
      redirect_to article_path(@article)
    else
      render :new
    end
  end

  def show
    @article = Article.find(params[:id])
  end

  def edit; end

  def update
    if @article.update(article_params)
      redirect_to article_path(@article)
    end
  end


  def destroy
    @article.destroy!
    redirect_to articles_path
  end

  private

  def article_params
    params.require(:article).permit(:title, :body)
  end

  def set_article
    @article = current_user.articles.find(params[:id])
  end
end
  • app/views/comments/_form.html.erb
<%= form_with model:comment, url: article_comments_path(article) do |form| %>
  <%= form.label :body, "本文" %>
  <%= form.text_area :body %>
  <%= form.submit "投稿する"%>
<% end %>

ここまでコード実装したところで、ログにActionController::ParameterMissing (param is missing or the value is empty: comment):が出てしまいました。

エラー解消方法

上記のエラーをそのまま検索にかけました。
こちらの記事のコメントが非常にわかりやすく、最初こちらの手順で確認を進めました。

1, コントローラーのnewアクションで、インスタンス変数が定義できていない?
``ActionController::ParameterMissing (param is missing or the value is empty: comment):```でのエラー発生原因の多くは、コントローラーのnewアクションで、インスタンス変数が定義できていないこととのこと。
上記を踏まえ、Commentsコントローラーのnewアクション、およびStrongパラメーターでタイポ等がないか確認しましたが、どちらも定義できていそう...。

2, form_withを作っているviewファイルで、モデルを指定していない?
app/views/comments/_form.html.erbも確認しましたが、<%= form_with model:comment, url: article_comments_path(article) do |form| %>のパーシャルファイル内で、モデル定義もできているので問題なさそう...。

3, commentsコントローラーのStrongパラメーター内、require(:comment)の記述を削除してみる
こちらの方法は、上記記事にある通り根本的な解消には至りませんでしたが、DBにコメント入力内容は登録されてました。ただ、下記警告内容がサーバーログに表記されていることもあり、require(:comment)の記述は元に戻しました。

 Unpermitted parameters: :authenticity_token, :commit, :article_id. Context: { controller: CommentsController, action: create, request: #<ActionDispatch::Request:0x0000ffff91177280>, params: {"authenticity_token"=>"[FILTERED]", "body"=>"ssss", "commit"=>"投稿する", "controller"=>"comments", "action"=>"create", "article_id"=>"12"} }

ここからがエラー解消の役に立ちました

4, form_withに直接モデルを定義してみる
1-3まで試してみてどれも上手くいかなかったので、試しにcommentsコントローラーのnewアクションを削除し、form_withに下記の形でモデルを直接定義してみました。

<%= form_with model:Comment.new, url: article_comments_path(article) do |form| %>

すると、エラーが解消し問題なくDBにパラメーターが保存されました!

何が原因だったのか

4の方法で、form_withに直接モデルを定義した場合はDBにコメント入力内容が登録できる。しかし、commentsコントローラーのnewアクションで定義したインスタンス変数ではエラーが発生する。
ということは、インスタンス変数を定義する場所が違うのではないか?という発想に至りました。

そうです....今回コメント機能を実装したいのは「記事詳細画面の中」ということに改めて気づき、app/controllers/articles_controller.rbのshowアクション内に、コメントのインスタンス変数を定義しました。

  • app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  skip_before_action :require_login, only: [:index, :show]
  before_action :set_article, only: [:edit, :update, :destroy]

  def index
    @q = Article.ransack(params[:q])
    @articles = @q.result(distinct: true).includes(:user).order(created_at: :desc)
  end

  def new
    @article = Article.new
  end

  def create
    @article = current_user.articles.build(article_params)

    if @article.save
      redirect_to article_path(@article)
    else
      render :new
    end
  end

  def show
    @article = Article.find(params[:id])
    @comment = Comment.new
  end

  def edit; end

  def update
    if @article.update(article_params)
      redirect_to article_path(@article)
    end
  end


  def destroy
    @article.destroy!
    redirect_to articles_path
  end

  private

  def article_params
    params.require(:article).permit(:title, :body)
  end

  def set_article
    @article = current_user.articles.find(params[:id])
  end
end

このように変更したところ、エラー解消しました。
@comment = Comment.newの記述は、newアクション内に記述するという固定概念がなんとなくあったため、エラー解消まで時間を要しましたが改めて学習できたのでよかったです。
ありがとうございました。

参考記事

【Rails】param is missing or the value is empty:について

Discussion