はじめに
本記事は、駆け出しエンジニアの第一歩!AdventCalendar2020 19日目の記事です。
アプリケーション概要
ユーザー投稿に対して、コメントができる一般的なアプリケーションです。(ユーザー登録はdeviseを使用)
現状では、commentに対するバリデーションは設定していないため、空投稿が可能な状態になっています。
ER図
コメント機能
実装前のコメント機能のviewとcontrollerは以下の通りです。
<%= form_with model:[@post_image, @comment], local:true do |f| %>
<div class="row">
<div class="col-sm-12">
<%= f.text_area :comment, rows:'5', class: "form-control",placeholder: "コメントをここに" %>
</div>
</div>
<%= f.submit "送信する", class: "btn btn-lg btn-base-1 mt-20 pull-right" %>
<% end %>
def show
@post_image = PostImage.find(params[:id])
@comment = Comment.new
end
def create
post_image = PostImage.find(params[:post_image_id])
comment = current_user.comments.new(comment_params)
comment.post_image_id = post_image.id
comment.save
redirect_to post_image_path(post_image)
end
private
def comment_params
params.require(:comment).permit(:comment)
end
コメント機能にエラーメッセージをつける
1. コメントモデルのバリデーション設定
validates :comment, presence: true
2. コントローラを条件分岐させる
ローカル変数commentのsaveに失敗した場合、commentはエラー内容を含んだものであるとわかる。その状態をviewに反映させる(エラーメッセージ を表示する)ために、インスタンス変数@error_commentにエラー内容を含んだcommentを再定義する必要がある。
def create
post_image = PostImage.find(params[:post_image_id])
comment = current_user.post_comments.new(comment_params)
comment.post_image_id = post_image.id
#6行追加(if〜end)--------------------------------
if comment.save
redirect_to post_image_path(post_image)
else
@error_comment = comment
render 'post_image/show'
end
#-----------------------------------------------
end
private
def comment_params
params.require(:comment).permit(:comment)
end
3. エラーメッセージの表示を記載する
さっき再定義した@error_commentをviewに渡す。
<%= form_with model:[@post_image, @post_comment], local:true do |f| %>
----エラーメッセージの表示を追加------------------------------------------------
<% if @error_comment.present? %>
<div id="error_explanation">
<h2><%= @error_comment.errors.count %>件のエラーが発生しました。</h2>
<ul>
<% @error_comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
--------------------------------------------------------------------------
<div class="row">
<div class="col-sm-12">
<%= f.text_area :comment, rows:'5', class: "form-control",placeholder: "コメントをここに" %>
</div>
</div>
<%= f.submit "送信する", class: "btn btn-lg btn-base-1 mt-20 pull-right" %>
<% end %>
2行目の<% if @error_comment.present? %>でエラーがあるときのみ、表示されるようにする。@error_commentは、commentが空の投稿の時のみ再定義される変数のため、showページを表示するときには定義されていない。
<% if @error_comment.present? %>がないと以下のようなエラーが出る。
4. post_imageのshowアクションの内容をcreateアクションに追記する
コメント投稿が失敗した場合、post_imageのshowページへrenderするようにしてあるが、showのviewを表示するのに必要なインスタンス変数がcommentコントローラのcreateアクションにはないので、追記してやる必要がある。
def show
@post_image = PostImage.find(params[:id])
@post_comment = PostComment.new
end
追記する。
def create
post_image = PostImage.find(params[:post_image_id])
comment = current_user.post_comments.new(post_comment_params)
comment.post_image_id = post_image.id
if comment.save
redirect_to post_image_path(post_image)
else
@error_comment = comment
#------post_imageのshowアクションを追加---------------
@post_image = PostImage.find(params[:id])
@post_comment = PostComment.new
#-------------------------------------------------
render 'post_image/show'
end
end
private
def comment_params
params.require(:comment).permit(:comment)
end
これでコメント投稿を実行しても、idがないので見つけることができないという以下のようなメッセージが出る。正確にはidはあるけど名称が変わって違うものになっているのでidを見つけることができないという感じ。
rails routesで確認すると、
Prefix | Verb | URI Pattern | Controller#Action |
---|---|---|---|
post_image | GET | /post_images/:id(.:format) | post_image#show |
post_image_comments | POST | /post_images/:post_image_id/comments(.:format) | comment#create |
showアクションではpost_imagesのパラメーターidは:idであったが、createアクションの場合、パラメーターidはpost_image_idとなっている。そのため、パラメーターidをpost_image_idに変更する。 |
def create
post_image = PostImage.find(params[:post_image_id])
comment = current_user.post_comments.new(post_comment_params)
comment.post_image_id = post_image.id
if comment.save
redirect_to post_image_path(post_image)
else
@error_comment = comment
#----------変更(:id → :post_image_id)------------------------
@post_image = PostImage.find(params[:post_image_id])
#------------------------------------------------------------
@post_comment = PostComment.new
render 'post_image/show'
end
end
private
def comment_params
params.require(:comment).permit(:comment)
end
まとめ
非常に回りくどい説明になりましたが、初学者の方でエラー解決に苦労している方などの参考になれば幸いです。