OneDay

40歳からプログラマとして生活しています。

ParameterMissing (param is missing or the value is empty: comments)

表題のエラーが出たので、何がいけなかったかレビューしてみます。

久々にCommentというモデルを作成しました。
ユーザー様のWebページ上を訪れたときにコメントを残せるようにするのが目的です。既に存在するusers#show内にコメント作成のフォームを組み込みます。

bin/rails g model Comment body:text user:references
bin/rails g controller comments create


最初に表題のエラーが出現したコードを載せます。

#users_controller.rb
(略)
def show
  @user = User.find(params[:id])
  @comment = Comment.new #追加
end
(略)

#views 
(略)
  <%= render 'shared/comment_form' %> #追加
(略)

#views/shared/_comment_form.html.erb #新規作成
<%= form_for @comment ,method: :post do |f| %>
    <%= f.text_area :body %>
    <%= f.submit '作成' %>
<% end %>

# comments_controller.rb
(略)
  def create
      @comment = Comment.new(user_id: params[:id])
      @comment.assign_attributes(params_comment)

      if @comment.save
          flash.notice = "コメントありがとうございました"
          redirect_to user_path(params[:id])
      else
          flash.now.alert = '登録出来ませんでした。'
          redirect_to user_path(params[:id])
      end
  end

  private
  def params_comment
      params.require(:comment).permit(
            :body
          )
  end
end

#config/routes.rb
  (略)
  resources :users
  post 'comments' => 'comments#create'  #追加
  (略)

さて、これ実行するとviewにテキストボックスと作成ボタンが表示されますが、コメントを入力して作成ボタンを押すと表題に書いたエラーが出ます。

ParameterMissing (param is missing or the value is empty: comments)



修正していきます。振り返って一番重要だと思ったのはルート設定です。私はPOSTだけを使おうとしています。POSTの場合 "POST /comments(.:format)"という形でurlが生成されるのでuser識別に用いるような個別の:idはありません。users#showは"GET /users/:id(.:format)"ですから、その:idが使えると私は錯覚してしまったわけです。ですので上記のエラーはparams.requireの記述が間違えっているのではなく、Comment.new(user_id: params[:id])のparams[:id]がないことで発生したもののようです。


では、users#showの"GET /users/:id(.:format)"の:idをcomments#postに引き渡すかが次の課題となります。私は次のように致しました。

  1. users#showでuser_idの情報をインスタンス変数@commentに持たせる。@user = User.find(params[:id]); @comment = Comment.new(user_id: @user.id)
  2. _comment_form.html.erbの中にhidden_fieldをセットしてcomments#createにuser_idの情報が行くようにする。(略)<%= f.hidden_field :user_id %>(略)
  3. comments#createのparams.require(:comment).permitの要素に:user_idを追加する。

この流れで:user_idが引き渡せて無事にuser_id固有のコメントが生成できるようになります。


もう一つ修正しなければいけません。Databaseへ書き込んだ後のredirect_to user_path(params[:id])です。同様にparams[:id]がありません。こう変えます。
ストロングパラメータでセットしたusesr_idを読み込みます。

redirect_to user_path(params_comment[:user_id])

これでコメントを書き込んだ後に、コメントを書いたユーザーの画面にリダイレクトします。


修正後

#users_controller.rb
(略)
def show
  @user = User.find(params[:id])
  @comment = Comment.new(user_id: @user.id) #さらに修正
end
(略)

#views 
(略)
  <%= render 'shared/comment_form' %> 
(略)

#views/shared/_comment_form.html.erb 
<%= form_for @comment ,method: :post do |f| %>
    <%= f.text_area :body %>
    <%= f.hidden_field :user_id %> #追加
    <%= f.submit '作成' %>
<% end %>

# comments_controller.rb
(略)
  def create
      @comment = Comment.new #修正
      @comment.assign_attributes(params_comment)

      if @comment.save
          flash.notice = "コメントありがとうございました"
          redirect_to user_path(params_comment[:user_id]) #さらに修正
      else
          flash.now.alert = '登録出来ませんでした。'
          redirect_to user_path(params_comment[:user_id]) #さらに修正
      end
  end

  private
  def params_comment
      params.require(:comment).permit(
            :body, :user_id    #ココ修正
          )
  end
end

#config/routes.rb
  (略)
  resources :users
  post 'comments' => 'comments#create'  
  (略)


私は来月でプログラミング歴2年になりますが、railsフレームワークや哲学は好きですね。日々のトライ・アンド・エラーの中で発見があり、少しずつプログラマーとして成長していると思います。2ヶ月くらいでrailsが合わないっすというようなブログを拝見しましたがたった2ヶ月で見切るなんて、勿体無いです。
私の2ヶ月はRubyの基礎の本を繰り返し読んで、基礎力を積み重ねていたなぁ。