HermannHH
HermannHH

Reputation: 1772

Rails Remote form validation errors not showing

I have created an ajax form in Rails 4 using remote: true. For some reason that I'm missing, my validation errors are not showing in the form.

Here is my current codebase:

1. Form

= simple_form_for @foo, url: foos_path, as: :foo, remote: true do |f|

  .row
    .input-field
      = f.input :bar

  .right-align.card-button
    = f.button :submit, class: "waves-light blue", data: { disable_with: "Loading..." }

2. create.js.erb

$("#new_foo").html('<%= j render_cell :foo, :form, foo: @foo %>');

3. Controller

def create
  @foo = FooForm.new( Foo.new )
  respond_to do |format|
    if @foo.validate(params[ :country ])
        @foo.save
        format.html { redirect_to root_path }
        format.json { render :show, status: :created, location: @foo.model }
        format.js 
    else
      format.html { render :new }
      format.json { render json: @foo.errors, status: :unprocessable_entity }
      format.js 
    end
  end
end

I would expect this code to show validation errors after a for being submitted incorrectly. Yet for some reason nothing happens after an incorrect submission. I can confirm that the form is being submitted however since the submission is processed in the log.I can also confirm that the form works perfectly fine when I remove remote submission.

Is there anything that I'm missing?

PS. I am using the Reform gem which might make my controller object code seem a little bit unfamiliar to a lot of people. I am rendering a cell in my js file as per this gem

UPDATE I have struggled with this some more. I implemented a solution that I've copied a 'remote: true' solution that I've built in a previous app, verbatim. This worked flawlessly in my previous app but does not display validation errors in my new app. The only difference between these two apps are the version of Ruby and Rails.

In the first app I ran Ruby: 2.2.1 with Rails: 4.2.2. My new app ('the one that I can't get working') I'm running Ruby: 2.2.3 with Rails: 4.2.4.

Could this perhaps have an impact??

Upvotes: 6

Views: 7085

Answers (4)

Vikas Vishwakarma
Vikas Vishwakarma

Reputation: 1

In newer versions of Rails, validation errors are not displayed unless a proper status code is set when rendering the form again. The issue occurs because render :new alone does not trigger the validation error messages correctly.

Ensure that when render :new is used, the status code is explicitly set to :unprocessable_entity (422).

Updated Code:

def create
  @foo = FooForm.new(foo_params)

  if @foo.save
    redirect_to @foo, notice: 'Foo was successfully created.'
  else
    render :new, status: :unprocessable_entity
  end
end

Why This Works?

Without status: :unprocessable_entity, Rails may treat the response as a successful request, preventing error messages from appearing. Setting the correct status code (422) ensures that Rails properly handles validation failures and re-renders the form with errors.

Upvotes: 0

Tomas Maly
Tomas Maly

Reputation: 21

The reason why it doesn't work is because AJAX defaults to expecting parseable javascript as a response, not json objects itself. you need to adjust $.ajaxSetup with dataType: json, or pass 'json' as a final parameter to $.post (after the callback) so it'll default to anticipating json.

Upvotes: 2

HermannHH
HermannHH

Reputation: 1772

After many hours I have finally managed to solve this issue. Still not sure why this is happening but I am posing the answer here in case somebody else ever experiences something similar. This Stackoverflow answer led me in the right direction.

I needed to add this line into my create action:

format.js    { render layout: false, content_type: 'text/javascript' }

Thus my full create action now looks like this:

def create
  @foo = FooForm.new( Foo.new )
  respond_to do |format|
    if @foo.validate(params[ :country ])
        @foo.save
        format.html { redirect_to root_path }
        format.json { render :show, status: :created, location: @foo.model }
        format.js 
    else
      format.html { render :new }
      format.json { render json: @foo.errors, status: :unprocessable_entity }
      format.js   { render layout: false, content_type: 'text/javascript' }
    end
  end
end

Upvotes: 7

codeurge
codeurge

Reputation: 130

From looking over the code, the only thing I saw that seems even slightly out of sorts - is the render call. Correct me if I'm wrong, but currently wouldn't you be returning the errors as the model object, whereas I think you'd need to provide it with the errors key.

format.json { render json: {errors: @foo.errors}, status: :unprocessable_entity }

Or, additionally I believe if you were to just return the object itself, the errors would be properly mapped to an errors key within the object.

format.json { render json: @foo, status: :unprocessable_entity }

Upvotes: 1

Related Questions