[RUBY] [Rails] I implemented the validation error message by asynchronous communication!

I'm a beginner with "super" who is struggling with Rails every day. Share for organizing your own knowledge.

Introduction

The other day, I learned how to implement asynchronous communication in Rails, but I haven't fully digested it, so I'll output it to deepen my understanding! Assuming a site that posts user-recommended books, you can comment on the posted books.

This time, when you press the send button with the comment field blank, the error message will appear directly above the comment field, and the error message itself will be implemented by asynchronous communication. Let's go fast!

Validation

models/comment.rb


class BookComment < ApplicationRecord

  belongs_to :user  #Link to User model
  belongs_to :book  #Linked to Book model

  validates :body, presence: true, length: {maximum: 150}
end

By setting presence: true in the comment model, posting in the blank is prohibited. By the way, I also set length: {maximum: 150}.

Let's check the controller right away!

Comments controller

comments_controller.rb


class BookCommentsController < ApplicationController
  before_action :authenticate_user!  #Allow access only to logged-in users

  def create
    @book = Book.find(params[:book_id])
    @comment = Comment.new(comment_params)  #Validation check is applied at this timing!
    @comment.book_id = @book.id
    @comment.user_id = current_user.id
    unless @comment.save  #@If the comment could not be saved
      render 'error'      #comments/error.js.Calling erb(See below)
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:comment)
  end
end

Using the value passed through the parameter, I am registering it in the database with the new method and save method. At that time, the foreign keys book_id and user_id cannot be obtained by parameters, so they are set at this timing. Well, is it all right so far?

The important thing here is that the validation check is done just before it is saved in the database, so the instance variable to get in the error statement is @comment = Comment.new(comment_params) Is that. In other words, it checks whether the value itself that has passed the parameter contains an error.

Next, the comment section is on the details page of Book, so let's check the controller of Books!

Books controller

books_controller.rb


class BookController < ApplicationController
  before_action :authenticate_user!  #Allow access only to logged-in users

  def show
    @book = Book.find(params[:id])
    @comment = Comment.new  #Comments new method for passing values to the controller
  end
end

There will be no problem here either! You have reached the turning point. Let's check the details page of Book at this pace!

Books show page

ruby:app/views/books/show.html.erb


  <div id="comments_error">
    <%= render 'layouts/errors', model: @comment %>
  </div>

  <%= form_with model:[@book,@comment] do |f| %>
    <%= f.text_area :comment %>
    <%= f.submit 'Send'%>
  <% end %>

In the part of comments_error in the first half, _errors.html.erb of layouts is called by render.

Also, I have provided a comment input field using form_with, but I want to set asynchronous communication, so I will not describe local: true. In the case of form_with, asynchronous communication is used by default, so there is no need to write remote: true.

Partial part of the error message

ruby:app/views/layouts/_errors.html.erb


<% if model.errors.any? %>
  <div id="error_explanation">
    <h3>
      <%= pluralize(obj.errors.count, "error") %> prohibited this model from being saved:
    </h3>

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

Do you remember calling with render from the Show page of Books? The error message is finally here. errors.full_messages gets all the error messages as an array. Since it is assumed that you are caught in multiple errors, we are looping with each method. Since this error statement is included by default, it can be used in various situations other than the comment section.

Js file used for asynchronous communication of error messages

ruby:app/views/comments/error.js.erb


$("#comments_error").html("<%= j(render 'layouts/errors', model: @comment) %>");

In books / show.html.erb, it is the process to rewrite the part ofid = "comments_error". Targeting id =" comments_error " with $ ("# comments_error "), it is rewritten with the contents of layouts / _errors.html.erb specified in render'layouts / errors'.

In addition, it is @ comment passed to model here, but do you know where this is defined? You used to call the js file with the Comments controller. That is, defined in the create action in the Comments controller, @comment = Comment.new(comment_params) Is passed to layouts / _errors.html.erb.

Hmmm, it's complicated! !!

(Supplement) The js file of the comment function itself is also described.

ruby:app/views/comments/create.js.erb


$(".comments").html("<%= j(render 'comments/index', book: @book) %>");
$("#comment_comment").val("");

Screen image

By implementing asynchronous communication image.png If you try to send a comment with blank as it is, image.png I was angry as I expected. This completes the error message using asynchronous communication! It is possible to convert the message text into Japanese, but due to space limitations, this is another opportunity.

in conclusion

Asynchronous communication has a lot of controllers and page-to-page transitions, so it's very confusing. If you read it a few times, I think it will bring you closer to understanding. If you get angry about the process flow, you may be able to shorten the implementation time. Excuse me. Let's study hard together!

Recommended Posts

[Rails] I implemented the validation error message by asynchronous communication!
Posting function implemented by asynchronous communication in Rails
I tried to implement the like function by asynchronous communication
[Rails] Let's translate the error message into Japanese
[Rails] Japanese localization of validation error message ~ ja.yml ~
[Rails, JavaScript] Implemented like function (synchronous / asynchronous communication)
[Rails 6] Validation by belongs_to
Rails ~ Understanding the message function ~
[Java] I implemented the combination.
I got a warning message with the rails _6.0.3_ new hello_myapp command
I tried to translate the error message when executing Eclipse (Java)
I implemented Rails API with TDD by RSpec. part2 -user authentication-
I want to control the default error message of Spring Boot
I implemented Rails API with TDD by RSpec. part3-Action implementation with authentication-
I don't see an error in Rails bundle install ... the solution
[Rails] Unexpected validation error in devise
[Rails] I tried deleting the application
I tried connecting the dot counter to the MZ platform by serial communication
I implemented Rails API with TDD by RSpec. part1-Action implementation without authentication-
I want to display an error message when registering in the database
Asynchronous communication in the interactive comment field
Implemented follow function in Rails (Ajax communication)
About the error message Invalid redeclaration of'***'
Get the error message using the any? method
[Rails 6] Asynchronous (Ajax) follow function is implemented
Until custom validation by annotation is implemented in Spring Framework and message is output
[Ruby on Rails] How to Japaneseize the error message of Form object (ActiveModel)