LoginSignup
19
14

More than 3 years have passed since last update.

RailsでAjaxのエラーメッセージを出す

Last updated at Posted at 2020-06-06

目標

ezgif.com-video-to-gif (2).gif

RailsでAjaxを用いてバリデーションに引っかかった時、エラーメッセージを出す。

Ajaxの例としてコメント機能で書きます。

環境

環境 rails 6.0.2.2

簡略的に、Userモデル(nameカラムとemailカラム)、Topicモデル(contentカラムとuser_idカラム)、Commentモデル(reviewカラムとuser_idとtopic_id)とします

Twitterに例えると、Userがツイート(Topic)し、そこにUserがCommentするといった感じです!

以下モデルの関連付けとバリエーション(Commentのみ)です。

user.rb
has_many :topics, dependent: :destroy
has_many :comments, dependent: :destroy
topic.rb
belongs_to :user
has_many :comments, dependent: :destroy
comment.rb
belongs_to :user
belongs_to :topic

validates :review, presence: true, length: { maximum: 150 }

Commentモデルはreviewカラムが「からの時」と「151文字以上」の時にエラーになります。

コントローラー

まずコントローラーを書いていきます。

topics_controller.rb
def show
  @topic = Topic.find[:params]
  @comment = Comment.new
  @comments = @topic.comments
end
comments_controller.rb
def create
    @topic = Topic.find(params[:topic_id])
    @comment = @topic.comments.build(comment_params)
    @comment.user_id = current_user.id
    @comment.save
  end

  def destroy
    @comment = Comment.find(params[:id])
    @comment.destroy
  end

コメントはtopics/show.html.erbでできるようにしています。

ビュー

次はビューです

topics/show.html.erb
<div id="comments_area">
    <%= render partial: 'comments/index', locals: { comments: @comments } %>
  </div>
  <div id="error_explanation">
  </div>
  <div id="form_area">
  <% if current_user %>
    <%= render partial: 'comments/form', locals: { comment: @comment, topic: @topic } %>
  <% end %>
</div>
comments/create.js.erb
$("#comments_area").html("<%= j(render 'index', { comments: @comment.topic.comments }) %>")
$("#error_explanation").html("<%= j(render 'error', { comment: @comment }) %>")
$("textarea").val("")
_form.html.erb
<%= form_with(model: [topic, comment]) do |f| %>

<% if comment.errors.any? %>
      <div id="error_explanation">

        <ul>
          <% comment.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
  <% end %>

  <div>
    <%= f.label :review %><span style="color: #f00;">(150文字以内)</span><br>
    <%= f.text_area :review,placeholder: "コメントはこちら" %>
  </div>
  <div class="actions mb-3">
    <%= f.submit "コメントをする", class: "btn btn-x btn-outline-secondary" %>
  </div>
<% end %>
comments/_index.html.erb
<% comments.each do |comment| %>
  <% unless comment.id.nil? %>
    <p><%= link_to "#{comment.user.name}さん",user_path(comment.user.id) %></p>
    <p><%= comment.review %></p>
    <% if comment.user == current_user %>
      <p><%= link_to "コメントを削除する",topic_comment_path(comment.topic_id,comment.id),method: :delete, remote: true %></p><hr size="5px" color="black">
    <% end %>
  <% end %>
<% end %>
comments/_error.html.erb
<% if comment.errors.any? %>
  <div class="error_message alert alert-warning">
    <ul>
      <% comment.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

流れとして
①topics/show.html.erbにアクセスすると、_form.html.erbと_index.html.erbが表示されている。indexはすでに保存されているコメントを表示しているhtml。

②formで「コメントをする」ボタンを押すと、commentコントローラーのcreateメソッドが実行される。この時、form_withはデフォルトでremote: trueになっているので、ビューは「create.js.erb」を探す。
(ちなみにlocal: trueとすればcreate.html.erbを探す)

③create.js.erbの1行目では、idがcomments_areaのところに_index.html.erbを表示させている。
2行目では同じように_error.html.erbを表示させている。ただエラーの方を見ると、if構文になっていて、エラーがなければ表示されない。3行目はformのtextareaを空にするコード。

これでエラーが表示されるようになります。

その他

一応ルートとコメント削除のビューも書いておきます。

routes.rb
resources :topics do
    resources :comments, only: [:create, :destroy]
  end
destroy.js.erb
$("#comments_area").html("<%= j(render 'index', { comments: @comment.topic.comments }) %>")
$("textarea").val("")

以上です!何かおかしいところなどありましたら、ご指摘下さい!

参考 http://eifukun.hatenadiary.jp/entry/2016/01/20/001011

19
14
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
19
14