如何在 rails 表单上使用 ajax 以及如何从服务器获取验证错误?

How to make work of ajax on rails forms and how to get validation errors from server?

我正在尝试将 this rails 教程应用到我的项目中。我制作了创建动作作品。我在我的模型文件中添加了一些验证。 现在,问题来了。当我提交参赛表格时,rails 一定会出错。在正常的 html 方式中,我可以看到错误。但是这个 ajax 风格的页面我无法让它工作。

当我发送空表格时,我无法收到 full_message 验证错误。

我在控制台上的错误

Started POST "/personels" for 127.0.0.1 at 2021-02-05 11:38:18 +0300
Processing by PersonelsController#create as JS
  Parameters: {"authenticity_token"=>"79VVfQ99zFbghWb7jMgjJzYb021qIeAQwte/XPCdSAEWF+SiC9gD11i4ZMoTJayPf+oZlJZplt6w8AwDmZ1+6g==", "personel"=>{"name"=>"", "surname"=>""}, "commit"=>"Create Personel"}
  Rendering personels/create.js.erb
  Rendered personels/_personel.html.erb (Duration: 0.7ms | Allocations: 1061)
  Rendered personels/create.js.erb (Duration: 0.8ms | Allocations: 1136)
Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.0ms | Allocations: 2760)


  
ActionView::Template::Error (No route matches {:action=>"edit", :controller=>"personels", :id=>nil}, missing required keys: [:id]):
    2:         <td><%= personel.name %></td>
    3:         <td><%= personel.surname %></td>
    4:         <td><%= link_to 'Show', personel %></td>
    5:         <td><%= link_to 'Edit', edit_personel_path(personel) %></td>
    6:         <td><%= link_to 'Destroy', personel, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    7: </tr>
  
app/views/personels/_personel.html.erb:5
app/views/personels/create.js.erb:2
app/controllers/personels_controller.rb:40:in `block (2 levels) in create'
app/controllers/personels_controller.rb:33:in `create'

我不是在编辑记录,但它似乎在尝试去 :action =>“编辑”。我不明白为什么会这样。

人事控制员

def create
    @personel = Personel.new(personel_params)

    respond_to do |format|
      if @personel.save
        format.html { redirect_to @personels, notice: 'Personel was successfully created.' }
        format.js
        format.json { render :index, status: :created, location: @personel }
      else
        format.html { render :new }
        format.js   { render layout: false , personel: @personel}
        format.json { render json: @personel.errors, status: :unprocessable_entity }
      end
    end
  end

人物模型

class Personel < ApplicationRecord
validates :name, :surname, presence: true
  belongs_to :journal_doc_analytic, optional: true

  def name_with_initial
    "#{name} - #{surname}"
  end
end

create.js.erb 文件

var personels = document.querySelector("#personels");
personels.insertAdjacentHTML("beforeend", "<%= j render(@personel) %>");

var personel_name = document.querySelector("#personel_name");
personel_name.value = ""

var personel_surname = document.querySelector("#personel_surname");
personel_surname.value = ""

var notice = document.querySelector("#notice");
notice.innerText = "Personel was successfully created."

setTimeout(function(){
  notice.innerText = "";
}, 2500);

_personel.html部分

<tr>
        <td><%= personel.name %></td>
        <td><%= personel.surname %></td>
        <td><%= link_to 'Show', personel %></td>
        <td><%= link_to 'Edit', edit_personel_path(personel) %></td>
        <td><%= link_to 'Destroy', personel, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
人员

index.html.erb

<p id="notice"><%= notice %></p>

<%= render 'form', personel: @personel %>
<h1>Personels</h1>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Surname</th>
      <th colspan="3"></th>
    </tr>
  </thead>

<tbody id="personels">
<%= render @personels %>
</tbody>
<br>
<%= link_to 'ORDER', personels_path(order: :asc) %>
<%= link_to 'ORDER desc', personels_path(order: :desc) %>

_form.html.erb部分

特别是我将这个脚本添加到下面的代码中: 错误 <%= personel.errors.full_messages.first %>

<script>window.addEventListener("load", () => {
  const element = document.querySelector("#new-personel");
  element.addEventListener("ajax:success", (event) => {
    const [_data, _status, xhr] = event.detail;
    element.insertAdjacentHTML("beforeend", xhr.responseText);
  });
  element.addEventListener("ajax:error", () => {
    element.insertAdjacentHTML("beforeend", "<p>ERROR <%= personel.errors.full_messages.first %></p>");
  });
});</script>

<%= form_with(model: personel, id: "new-personel", local: false) do |form| %>
  <% if personel.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(personel.errors.count, "error") %> prohibited this personel from being saved:</h2>

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

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :surname %>
    <%= form.text_field :surname %>
  </div>

  <div class="actions">
    <%= form.submit data: {disable_with: "Saving..."} %>
  </div>
<% end %>

路线

personels GET    /personels(.:format)                                                                     personels#index
                                      POST   /personels(.:format)                                                                     personels#create
                         new_personel GET    /personels/new(.:format)                                                                 personels#new
                        edit_personel GET    /personels/:id/edit(.:format)                                                            personels#edit
                             personel GET    /personels/:id(.:format)                                                                 personels#show
                                      PATCH  /personels/:id(.:format)                                                                 personels#update
                                      PUT    /personels/:id(.:format)                                                                 personels#update
                                      DELETE /personels/:id(.:format)                                                                 personels#destroy

我找到了解决办法。 我添加的新部分命名为:

** _error.html.erb **

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

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

并更新了我的 ** create.js.erb **

var errors = document.querySelector("#errors");
errors.replaceChildren("");

if (errors.childElementCount == 0){ 
errors.insertAdjacentHTML("beforeend", "<%= j render partial: '/personels/error' %>");
var notice = document.querySelector("#notice");
notice.innerText = "";
} else {
var notice = document.querySelector("#notice");
notice.innerText = "Personel was successfully created.";
}

var personels = document.querySelector("#personels");
personels.insertAdjacentHTML("beforeend", "<%= j render(@personel) %>");

var personel_name = document.querySelector("#personel_name");
personel_name.value = ""

var personel_surname = document.querySelector("#personel_surname");
personel_surname.value = ""

setTimeout(function(){
notice.innerText = "";
}, 2500);

结果是:

我的控制器是一样的。