Parsing JSON errors using simple_form and AJAX in rails - ruby-on-rails

I have a form that is using Simple Forms and remote => true on the users dashboard (which is handled by a dashboard view and dashboard controller). The form allows a user to add a custom game rule; however, it's loading the form via a Jquery's .load() function. The form is loading from the "rules" view (handled by a rules controller).
When the user clicks the submit button, I'm not getting any error validation.
Her is the create action on the rule controller:
def create
#rule = Rule.new(params[:rule])
respond_to do |format|
if #rule.save
format.html { redirect_to dashboard_path, notice: 'Rule was successfully created.' }
format.json { render json: #rule, status: :created, location: #rule }
format.js
else
format.html { render template: 'dashboard/index'}
format.json { render json: #rule.errors, status: :unprocessable_entity }
format.js
end
end
end
I've got a js file called create.js.erb in my views folder that is currently empty. I think that I have to somehow parse the JSON error data in this create.js.erb file, but I have no idea how to do it.
Also, does it matter that this form is being called by the Dashboard view/controller but the form is being handled by the Rule controller?

Try the following inside create.js.erb
$('.error-messages').remove();
<% if #rule.errors.any? %>
$('body').append('<ul class="error-messages"></ul>');
<% #rule.errors.full_messages.each do |msg| %>
$('.error-messages').append('<%= escape_javascript msg %>');
<% end %>
<% end %>
This will append the errors in your body tag.

Related

Getting status: code on ajax response in a .js.erb file on Rails

I've just started to play with Rails applications and I'm trying to use Ajax on a form, but I don't know how to catch the status code inside a js.erb file. I'm following this tutorial: http://guides.rubyonrails.org/working_with_javascript_in_rails.html
On my Users controller I have a code for my update method:
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.js {}
format.json { render json: #user, status: :created, location: #user}
else
format.html { render action: 'edit' }
format.js {}
format.json { render json: #user, status: :unprocessable_entity }
logger.debug #user.response_errors
end
end
I've created a update.js.erb file inside my views/users/ folder and is very easy to debug the #user var, but I don't know how to get the status code setted on my method.
Sorry if it's a stupid question, but I'm new with rails and I'm trying to follow all the frameworks concepts to the letter and I don't know the best pratices to create responses to Ajax requests.
What I'm trying to achieve is something like this:
#on my update.js.erb
if( status == 'created' ) {
alert( 'Ok, created' )
} else {
alert( 'Something wrong happened' )
}
I appreciate any help.
Option 1: Check Validity Inside update.js.erb
This is the option that I recommend in most cases.
update.js.erb is an ERB template whose result is a JavaScript code to evaluate on the client. In this case, you can make it look like:
<% if #user.valid? %>
alert('Ok, created');
<% else %>
alert('Something wrong happened');
<% end %>
The decision which alert to displays happens server-side. The client receives either:
alert('Ok, create');
or
alert('Something wrong happened');
depending on the status of #user.
Option 2: Two separate js.erb files
You can split your update.js.erb into two files. update.js.erb should contain the happy path code:
alert('Ok, create');
update-error.js.erb should contain some error handling:
alert('Something wrong happened');
Then you decide which one to display in your controller:
respond_to do |format|
if #user.save
# ...
format.js {}
# ...
else
# ...
format.js { render 'update-error' }
# ...
end
end
I would try to do:
format.js {render json: {#user, status: :created, location: #user}}

Rails flash notice in current view, before redirect

I need to flash a message, in the "new" view when the user submits the form, but, before the controller redirects to the "show" view.
I run a .sh script from the create method upon the submission of the form. The script takes a couple of minutes to run. The form sits inside the "new" view. The form etc.. were all scaffolded so using standard conventions.
How can I flash a message in the "new" view, before the .sh script runs and the controller redirects?
new.html.erb:
<p id="notice"><%= notice %></p>
<h1>New Job</h1>
<%= render 'form' %>
jobs_controller:
def create
#job = Job.new(job_params)
flash[:notice] = 'Job Started' #added notice here but it doesn't flash in the "new" view
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job finished' }
format.json { render :show, status: :created, location: #job }
else
format.html { render :new }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
job_call = 'sh testScript.sh' #var for a test sh file to run
system(job_call) #add sh script here
end
The flash message isn't happening because that only happens when Rails sends a Response back to the client (the browser) and the browser renders a template.
The Response is only sent back once everything in the create method has finished. This is the crux of your problem.
The blocker is that in Rails you can only do one redirect or render per controller method, even if you try to cheat and call another method that contains the second render or redirect. You get a AbstractController::DoubleRenderError.
I don't think there's a way round this and I don't think you could even achieve it with Rails AJAX. It looks like your Javascript solution is the only way. Why don't you post up your solution?
So, this is clearly a workaround to the problem. But I achieved it with unhiding a div or just flashing a JS alert with the notice message on the form submit:
<%= f.submit 'Run Job', :onclick => "return showNotice()"%>

Want to build updating status in rails

I am working on rails ..
Want to add status feature, but having problem as we need to go create and edit page of each status.
Want to know how can I do on the same page without leaving the page..
I would do something like:
<%= form_for(#status, remote: true) do |f| %>
...
<% end %>
Check out the Rails guide on ajax forms.
You can render back with json like:
def create
#status = Status.find(params[:id])
respond_to do |format|
if #status.update_attributes(status_attributes)
format.html { redirect_to #status }
format.js {}
format.json { render json: #status }
else
format.html { render action: "new" }
format.json { render json: #status.errors }
end
end
I edited this to reflect updating a status.

Modifying respond_to in Rails 3

Here is the premise:
I have a model called Rules, which has a corresponding controller and view.
I'd like the user to be able to create a new rule from their Dashboard, which has a separate view and controller.
The dashboard has three tabs called "Rules", "Rulesets, and "Games." Each tab has its own partial, so for Rules I'm using the _rules.erb partial which looks like this
<div id="dashboard-rules" class="dashboard-panel ui-nav-panel">
<%= button_to'Create A Rule', '#', id: "create-rule-btn", class: "btn btn-primary" %>
<div id="create-rule-form-container">
</div>
...
</div>
Using jQuery, I'm loading the contents of the New Rules page which is controlled by the Rules controller, like this...
$('#create-rule-btn').click (e) ->
e.preventDefault()
$('#create-rule-form-container').load('/rules/new.html .form-horizontal')
This loads just the form from rules/new.html. My problem is that when I click the "Save Rule" button, it redirects to the /rules URL. And then either displays errors or says "Rule Saved Successfully." I'd like for it not to redirect and have the errors show in the dashboard...again, not redirect to /rules URL.
This is my Rules create action, which I think needs to be modified, I'm just not sure how:
def create
#rule = Rule.new(params[:rule])
respond_to do |format|
if #rule.save
format.html { redirect_to #rule, notice: 'Rule was successfully created.' }
format.json { render json: #rule, status: :created, location: #rule }
else
format.html { redirect_to :controler => "dashboard"}
format.json { render json: #rule.errors, status: :unprocessable_entity }
end
end
end
I know I have to fiddle with how respond_to is working, I just don't know how.
Remember that you need to set all variable you set in your dashboard in the create action in order for the following to work. This is because you're rendering the same template as the dashboard so you need to set the variables again.
if #rule.save
format.html { redirect_to dashboard_path, notice: 'Rule was successfully created.' }
format.json { render json: #rule, status: :created, location: #rule }
else
# initialize the variables needed on the dashboard here
format.html { render template: 'dashboard/index' }
format.json { render json: #rule.errors, status: :unprocessable_entity }
end
One more solution is to submit the form via ajax and just refresh the page when the rule is saved.
UPDATE: quick js solution
in the form that creates the rules, add the following
form_for #rule, html: { remote: true } do |f|
This will submit the form via ajax. In your controller, add a format.js line after each format.json
format.json { ... }
format.js
then create a app/views/rules/create.js.erb (or haml) file. In the file, you can add any js you want so add the following
<% if #rule.errors.any? %>
# add js here to append the errors in the page
<% else %>
window.location.reload
<% end %>

How do I handle response from an Ajax Request in Rails 3?

I have a CRUD application set up in Ruby on Rails 3 - its working as is. I need to add some ajax here. My first requirement is to retrieve a customised form when clicking on a New Form link. This is the link I have at this point:
<%= link_to 'New Book', new_book_path(:subject_id=>#subject.id), :remote=>true %>
For my controller I've made the following adjustment to the new book action:
def new
#book = Book.new
if params[:subject_id].to_i >0 then
#book.subject_id = params[:subject_id]
end
if request.xhr?
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
render :layout => false, :file=>'app/views/books/_form'
return false
end
else
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
end
end
end
I checked in firebug and clicking on the link generated returns the form html however I have no idea how to handle the response? Please do help.
Instead of responding with HTML respond with .js
Inside your .js.erb file could be something like this
$("#idname").append(<%= render "form" %>)
That way it renders and returns the form HTML but also gives the js code to append the HTML.
You can certainly rely on Rails generated JavaScript, but I always like to have "more control" over my JavaScript code. In e.g. jQuery you could have something like this (untested), if you want to insert the partial (html) rendered by your controller into the site:
$("#new-book-button").click( function () {
$.get('books/new', function(data) {
$('#some-form-container').html(data);
});
}

Resources