Afolabi Olaoluwa
Afolabi Olaoluwa

Reputation: 1948

Validation errors not showing after I ajax a rails form

I am using ajax-rails to render my form and validations stopped working. When I click to submit empty for which should validate, validation does not take effect and backend log shows it posted empty form. If I don't use ajax it works fine. I don't know what I am missing.

model

class ClockEntry < ApplicationRecord
  belongs_to :user

  validates :purpose, presence: true # I validated the attribute
end

index.html.erb

<div class="container" id="new-clock-entry">
  <%= link_to 'New Clock Entry', new_clock_entry_path, remote: true, class: 'btn btn-primary btn-sm' %>
</div>

_form.html.erb

<%= simple_form_for clock_entry, remote: true do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

  <div class="form-inputs">
    <%= f.input :purpose %>
  </div>

  <div class="form-actions">
    <%= f.button :submit, class: 'btn btn-primary btn-block btn-lg' %>
  </div>
<% end %>

new.html.erb

<h1>New Clock Entry</h1>

<%= render 'form', clock_entry: @clock_entry %>

<%= link_to 'Back', clock_entries_path %>

new.js.erb

$('#new-clock-entry a').hide().parent().append("<%= j render 'form', clock_entry: @clock_entry %>")

create.js.erb

$('#new-clock-entry form').remove();
$('#new-clock-entry a').show();
$('table#clock-entry tbody').append("<%= j render @clock_entry %>");

controller

def new
  @clock_entry = ClockEntry.new
end

def create
    @clock_entry = current_user.clock_entries.new(clock_entry_params)
    @clock_entry.set_time_in

    respond_to do |format|
      if @clock_entry.save
        format.js { redirect_to root_path, notice: 'Clock entry was successfully created.' }
        format.html { redirect_to @clock_entry, notice: 'Clock entry was successfully created.' }
        format.json { render :show, status: :created, location: @clock_entry }
      else
        format.html { render :new }
        format.json { render json: @clock_entry.errors, status: :unprocessable_entity }
      end
    end
  end

Upvotes: 2

Views: 861

Answers (1)

Afolabi Olaoluwa
Afolabi Olaoluwa

Reputation: 1948

@arieljuod in the comments section was very instrumental to me solving this. As he mentioned firstly, I am not asking my format to respond to js under the else condition of the create method. So this is what I did:

controller create action

Add the line below to the else condition of the create action:

format.js { render :new }

So my controller action becomes:

def create
    @clock_entry = current_user.clock_entries.new(clock_entry_params)
    @clock_entry.set_time_in

    respond_to do |format|
      if @clock_entry.save
        format.html { redirect_to @clock_entry, notice: 'Clock entry was successfully created.' }
        format.js { redirect_to root_path, notice: 'Clock entry was successfully created.' }
        format.json { render :show, status: :created, location: @clock_entry }
      else
        format.js { render :new } # Added this...
        format.html { render :new }
        format.json { render json: @clock_entry.errors, status: :unprocessable_entity }
      end
    end
  end

new.js.erb file

Then in the new.js.erb file, upon rendering the :new form, you need to remove or hide what is already there and append a new form that has the error message. So I had to remove the whole form by supplying the form tag to be hidden in my new.js.erb. So I add this line below to my new.js.erb file:

$('#new-clock-entry form').hide().parent().append("<%= j render 'form', clock_entry: @clock_entry %>")

So new new.js.erb file now becomes:

$('#new-clock-entry a').hide().parent().append("<%= j render 'form', clock_entry: @clock_entry %>")
$('#new-clock-entry form').hide().parent().append("<%= j render 'form', clock_entry: @clock_entry %>")

I think this should be handy to anyone who runs into the same problem.

Upvotes: 2

Related Questions