Reputation: 1772
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
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
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
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
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