简体   繁体   中英

Rails Form_with display inline error message

I am trying to display the error message inline below the form elements in my rails application.

I did the following.

Controller

def create
    @faculty = Faculty.new(faculty_params)
    respond_to do |format|
        if @faculty.save
            format.html { redirect_to admin_faculties_path, notice: 'Faculty was successfully created.'}
            format.json {render json: @faculty, status: :created, location: @faculty}
        else
            format.html {render '_form'}
            format.json {render json: @faculty.errors, status: :unprocessable_entity }
        end
    end
end

Form

    <% form_with(model: [:admin, @faculty]) do |f| %>
<div class="card-title">Add Faculty</div>
    <div class="form-group">
        <%= f.label :faculty_name, class: "form-label" do %>
        Faculty Name <span class="form-required">*</span>
        <% end %>
        <%= f.text_field :faculty_name, class: "form-control", placeholder: "Faculty Name", required: true %>
    </div>
<%= f.submit class: "btn btn-primary" %>

As I have some validations rules in Model, it checks the validations and stop the form from submitting if the validations occurs. As, this is the form_with form all the requests are handled by Ajax. So, I am looking to display the validations errors below the each form elements. Please suggest me with examples so that I can complete this task.

You could check for every attribute's errors on your form fields and if that attribute has any error just show them

<% form_with(model: [:admin, @faculty]) do |f| %>
  <div class="card-title">Add Faculty</div>
  <div class="form-group">
    <%= f.label :faculty_name, class: "form-label" do %>
      Faculty Name <span class="form-required">*</span>
    <% end %>
    <%= f.text_field :faculty_name, class: "form-control", placeholder: "Faculty Name", required: true %>
    <% if @faculty.errors[:name].any? %>
      <ul>
        <% @faculty.errors[:name].each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    <% end %>
  </div>
<%= f.submit class: "btn btn-primary" %>

A better solution could be refactor that on a helper :

Helper

module FacultyHelper

  def inline_errors(model, model_attribute)
    result = ""
    if model.errors[model_attribute].any?
         model.errors[model_attribute].each do |message|
            result += "<li>#{message}</li>"
        end
    end
    return "<ul>#{result}</ul>".html_safe
  end
end

View [UPDATE: wrapper for name errors]

<% form_with(model: [:admin, @faculty]) do |f| %>
  <div class="card-title">Add Faculty</div>
  <div class="form-group">
    <%= f.label :faculty_name, class: "form-label" do %>
      Faculty Name <span class="form-required">*</span>
    <% end %>
    <%= f.text_field :faculty_name, class: "form-control", placeholder: "Faculty Name", required: true %>
    <div id="user_name_errors">
       <%= inline_errors(@faculty, :name) %>
    </div>
  </div>
<%= f.submit class: "btn btn-primary" %>

For remote: true, you need to define on your controller format.js

Controller

def create
    @faculty = Faculty.new(faculty_params)
    respond_to do |format|
        if @faculty.save
            format.html { redirect_to admin_faculties_path, notice: 'Faculty was successfully created.'}
            format.json {render json: @faculty, status: :created, location: @faculty}
            format.js
        else
            format.html {render '_form'}
            format.json {render json: @faculty.errors, status: :unprocessable_entity }
            format.js
        end
    end
end

Create a corresponding js.erb view

create.js.erb

$("#user_name_errors").html("<%= inline_errors(@faculty, :name) %>");

You can automate that by overriding ActionView::Base.field_error_proc

1 - Create an initializer: config/initializers/fields_with_errors.rb

2 - Add this code to it.

ActionView::Base.field_error_proc = proc do |html_tag, instance|
    html_doc = Nokogiri::HTML::DocumentFragment.parse(html_tag, Encoding::UTF_8.to_s)
    element = html_doc.children[0]

    if element
        element.add_class('is-invalid')

        if %w[input select textarea select].include? element.name
            instance.raw %(#{html_doc.to_html} <div class="invalid-feedback">#{[*instance.error_message].to_sentence}</div>)
        else
            instance.raw html_doc.to_html
        end
    else
        html_tag
    end
end

Read more about it how it works https://dev.to/etoundi_1er/show-rails-validation-errors-inline-with-bootstrap-4-4ga6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM