2

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
8
  • 2
    You don't have a format.js line on the else when @clock_entry.save fails. Don't you have an error saying it can't find the view? Commented Sep 26, 2019 at 18:40
  • @arieljuod Wow true. But when I added that it renders a new ajax form under the ajax form instead of rendering on the form. Now I have double forms. Commented Sep 26, 2019 at 18:54
  • I guess you are using "append" on your javascript without removing the old form. Commented Sep 26, 2019 at 19:13
  • Can you provide an answer for this? That will shed more light into it. Am not so crafted with Ajax Commented Sep 26, 2019 at 19:16
  • I'm not sure what's your current view and your current ajax response. You have to target the element you don't want, call "remove()" and then append the new form. Commented Sep 26, 2019 at 19:39

1 Answer 1

2

@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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.