I am trying to apply this rails tutorial to my project. I made create action works. I added some validation to my model file. Now, problem comes here. When i submit entry form, rails must give errors. In the normal html way i can see the errors. But this ajax style page i can't make it work.
When i'am sending empty form, i can't get full_message validation error.
My error on console
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'
I am not editing record but it seems to trying to go :action => "edit". I don't understand why it is like happens.
Personel Controller
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
Personel Model
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 file
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 partial
<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 of Personel
<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 Partial
Espacially i added this script to code below : ERROR <%= 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 %>
Routes
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
I found the solution. I added new partial is named:
** _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 %>
and updated my ** 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);
My controller is same.