如何在 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);
结果是:
我的控制器是一样的。
我正在尝试将 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);
结果是:
我的控制器是一样的。