This might be one of the more difficult questions I've asked, but I have been stuck for a few days, and I thought it'd be best to get support from the more experienced rails community.
I am working on a dummy app that follows this guide roughly... ajax/jquery tutorial...
Making my own customizations, the guide helped me to create a "brand" (includes nested models "model", "submodel", and "style") submission form (using simple_form) and brands listing on the same page.. This works perfectly, and the validation (for my models) is enforced.. However, when I put the form and brand listing on the same page I lose the neat inline validation errors that were appearing on submission failure (see image below). Not being able to get the inline errors to work has made me realize that I have more to learn about rendering.. and that is why I am fixated on finding the answer to this question
...and here is the listing:
Below is the controller for the index action:
def index
#This is for the product listing
@brands = Brand.all.reverse
#This is for the form
@brand = Brand.new
@model = Model.new
@submodel = Submodel.new
@style = Style.new
respond_to do |format|
format.html
end
end
The above form creates the brand, model, submodel, and style for use in the nested submission form... Below is the code for the form:
<%= simple_form_for @brand, :html => { :class => 'form-horizontal' }, :remote => true do |m| %>
<fieldset style = "margin-top:34px;">
<legend></legend>
<%= m.input :name, :label => 'Brand' %>
<%= m.simple_fields_for :models, @model do |p| %>
<%= p.input :name, :label => 'Model' %>
<%= p.simple_fields_for :submodels, @submodel do |s| %>
<%= s.input :name, :label => 'Submodel' %>
<%= s.simple_fields_for :styles, @style do |ss| %>
<%= ss.input :name, :label => 'Style' %>
<% end %>
<% end %>
<% end %>
<div class="form-actions">
<%= m.submit nil, :class => 'btn btn-primary' %>
<%= link_to 'Cancel', brands_path, :class => 'btn' %>
</div>
</fieldset>
<% end %>
Now as you can see I am using :remote => true
... I would like for the form to either create the new "brand", or for the form to reload with inline validation errors. At the moment my create action looks like:
def create
@brand = Brand.new(params[:brand])
respond_to do |format|
if @brand.save
format.html { redirect_to brands_url, notice: 'Brand was successfully created.' }
format.json { render json: @brand, status: :created, location: @brand }
format.js
else
format.html { render action: "index" }
format.json { render json: @brand.errors, status: :unprocessable_entity }
format.js { render 'reload' }
end
end
end
The code that appears under if @brand.save
seems to work.. but the code below "else" doesn't work the way I'd like. So what is happening when @brand does NOT save? I believe that the code within the index action is being run, then @brand.errors is converted to json (which I assume is for the simple_form validation errors), and then reload.js.erb is being run..
In an attempt to reload the form (with validation errors) I have put the line $("#entryform").load(location.href+" #entryform>*","");
into reload.js.erb ... When I put invalid data into my form reload.js.erb is being called, but all that happens is that the form fields reload blank, instead of having the data entered and inline validation errors.
I hope I have provided enough info here to get help.. Really struggling on this one. Thanks!
I think you can simplify this by putting your form in a partial (we'll call it simple_form
), and putting this code in reload.js.erb:
$("#entryform").html("<%= escape_javascript(render :partial => 'simple_form') %>");
I'm not familiar with jQuery's load
method, but I assume it does a second request. The key with rendering errors is the instance variable (@brand
) you're using while rendering the form has to be the same one you tried to save in create, so you can check the errors on it. This is why you always use render
instead of redirect_to
when you want to render errors. If you do a redirect, you start a new request, meaning @brand
is reinitialized. I'm assuming your $(...).load(...)
is having the same issue.
Thanks for all the Q&A on this one. It saved me.
Simplifying @tsherif's file structure one notch (assuming you already have a js file), I solved this issue by called render directly on the form and showing it via javascript/coffeescript.
#immediate_controller
def action_with_modal
@brand = params[:failed_brand] || Brand.new
end
#brands_controller
def create
@brand = Brand.new(params[:brand])
respond_to do |format|
if @brand.save
...
else
params[:failed_brand] = @brand
...
format.js { render 'simple_form' }
end
end
end
#coffeescript
$('form-selectors-here').on 'ajax:error', @reRegister
reRegister: (e, data) =>
$("div-that-contains-form").html(data.responseText)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With