LoginSignup
0
0

More than 1 year has passed since last update.

投稿に対する空コメントでInvalid dateが出たときの対処法

Last updated at Posted at 2021-10-24

目的

自作アプリで投稿にコメントができる機能を作成。
その際出てくるエラーの解決に時間がかかったので、解決までの考え方を備忘録として記事にしました。

環境

windows10 home
Ubuntu 20.04.1 on WSL2
rails 6.0.3
ruby 2.6.6

起きた現象

空のコメントを送信するとInvalid dateエラーが発生。
eae5c07bf8195a5b11daa98e2106ada6

コメントモデルのカラムは以下に記載

  • id
  • content(コメントの中身)
  • user_id(外部キー)
  • micropost_id(外部キー)
  • created_at
  • updated_at

①ビューを確認

microposts/show.html.erb
<% @comments.each do |c| %>
  <div class="d-flex"> 
    <div class="d-flex"> 
      <%= link_to user_path(c.user) do %> 
          <%= image_tag c.user.portrait.to_s, size: "40x40" %> 
      <% end %> 
    </div> 
    <div class="d-flex flex-column"> 
      <small class="text-muted"><%= c.user.name %></small> 
      <div> 
        <small><%= simple_format(h(c.content)) %></small> 
      </div> 
    </div> 
  </div> 
  <div class="d-flex flex-row mb-3 border-bottom border-dark"> 
    <div class="d-flex align-items-center"> 
      <small><%= Date.parse(c.created_at.to_s).strftime("%m月%d日") %></small>  <%# ここでエラー発生 %> 
    </div> 
    <% if c.user.id == current_user.id %> 
      <%= link_to "削除", micropost_comment_path(@micropost, c), method: :delete, data: {confirm: "コメントを削除しますか?"}, class: "btn btn-sm btn-light ml-2" %> 
    <% end %> 
  </div> 
<% end %>

日付を「〇〇月〇〇日」の形で表示させるところでエラーが発生している。
このメソッドは他のページでも使用しており、その際エラーがでていないことから
他の部分に不具合があり、それがここで引っかかっているのではないかと考えました。

②バリデーションを確認

まずはコメントモデルのバリデーションがちゃんと記述できているか確かめる。

comment.rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :micropost

  validates :content, presence: true, length: {maximum: 200}
  validates :user_id, {presence: true}
  validates :micropost_id, {presence: true}
end

モデルのバリデーションに問題はなさそう。
とすると、データベースのNotNull制約に何か問題があるのかも。

参考:【Rails】「テーブルのカラムに定義するNot Null制約」と「モデルに定義するバリデーション(presence: true)」の挙動の違い。

データベースの中身を調べてみる。

mysql> desc comments;
+--------------+-------------+------+-----+---------+----------------+
| Field        | Type        | Null | Key | Default | Extra          |
+--------------+-------------+------+-----+---------+----------------+
| id           | bigint      | NO   | PRI | NULL    | auto_increment |
| content      | text        | NO   |     | NULL    |                |
| user_id      | bigint      | NO   | MUL | NULL    |                |
| micropost_id | bigint      | NO   | MUL | NULL    |                |
| created_at   | datetime(6) | NO   |     | NULL    |                |
| updated_at   | datetime(6) | NO   |     | NULL    |                |
+--------------+-------------+------+-----+---------+----------------+
6 rows in set (0.03 sec)

ちゃんと:contentカラムにNotNull制約がついているのを確認。
どうやらバリデーションに問題はないみたい。

③コンソールで確認

次に空投稿が送信されたときの動きをコンソールで調べてみる。

pry(main)> c = Comment.new(user_id:33, micropost_id:76, content:"")
=> #<Comment:0x0000563201d95c18
 id: nil,
 content: "",
 user_id: 33,
 micropost_id: 76,
 created_at: nil,
 updated_at: nil>

pry(main)> c.save!
ROLLBACK
ActiveRecord::RecordInvalid: バリデーションに失敗しました: Contentを入力してください
from /home/XXXXX/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activerecord-6.0.3.5/lib/active_record/validations.rb:80:in `raise_validation_error'

contentが空のコメントはちゃんとバリデーションで引っかかっている。
...ん?じゃあなんでInvalid dateエラーになるんだ?
空コメントのインスタンスが何らかの原因でcreateされてるってこと?

④コントローラーを確認

投稿詳細ページにコメントを表示させるので、
コメントとマイクロポスト2つのコントローラーを確認する。

comments_controller.rb
class CommentsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_micropost

  def create
    @comments = @micropost.comments
    @comment = @micropost.comments.new(comment_params)
    @comment.user = current_user
    if @comment.save
      flash[:primary] = "コメントしました"
      redirect_to @micropost
    else
      flash.now[:danger] = "コメントを入力してください"
      render("microposts/show")
    end
  end
・・・
(略)
・・・
  private
    def set_micropost
      @micropost = Micropost.find_by(id: params[:micropost_id])
    end

    def comment_params
      params.required(:comment).permit(:content).merge(user_id: current_user.id, micropost_id: params[:micropost_id])
    end
end
microposts_controller.rb
def show
  @micropost = Micropost.find_by(id: params[:id])
  @comments = @micropost.comments
  @comment = Comment.new # コメントフォームのインスタンスはmicropost/showで作成
end

マイクロポストコントローラーに問題はなさそう。
そうなるとコメントコントローラーのcreateアクションに原因がありそう。

⑤原因判明

createアクションを見ていて最初に定義した@commentsと次に定義した@comment
@micropost.commentsに紐付いているということに気づいた。
createされた@commentはすぐに@micropost.commentsとして組み込まれる。

組み込まれた@commentをビューが表示しようとするが、
created_atがnilなのでInvalid dateエラーになる。
つまり@commentを定義するとき@micropostと紐付けるのをやめればいいのでは?

【変更前】

comment_controller.rb
・・・
def create
    @comments = @micropost.comments
    @comment = @micropost.comments.new(comment_params)
    @comment.user = current_user
    if @comment.save
      flash[:primary] = "コメントしました"
      redirect_to @micropost
    else
      flash.now[:danger] = "コメントを入力してください"
      render("microposts/show")
    end
  end
・・・

【変更後】

comment_controller.rb
・・・
def create
    @comments = @micropost.comments
    @comment = Comment.new(comment_params)  # 変更
    @comment.user = current_user
    if @comment.save
      flash[:primary] = "コメントしました"
      redirect_to @micropost
    else
      flash.now[:danger] = "コメントを入力してください"
      render("microposts/show")
    end
  end
・・・

無事成功。
書いてみると単純なことですがものすごい時間取られました。
image

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0