Modifying respond_to in Rails 3 - ruby-on-rails

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 %>

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 errors resets form params

This seems simple, but I can't find anything on it.
I have a link to request a meeting with another user. This produces a url like this:
http://localhost:3000/meetings/new?requestee_id=5
The requestee id, and other information in the form are passed to the MeetingController:
def create
requestor = current_user
#meeting_with_params = meeting_params
#meeting = Meeting.new(meeting_params)
respond_to do |format|
if #meeting.save
format.html { redirect_to home_url, notice: 'Your lex was successfully requested! Click Plan Meeting ' }
format.json { render :show, status: :created, location: #meeting }
else
format.html { render :new, params: #meeting_with_params }
format.json { render json: #meeting.errors, status: :unprocessable_entity }
end
end
end
If there are errors, the url now looks like this:
http://localhost:3000/meetings
which means the form will never submit since the requestee_id is not present.
What is right way to have the user see errors, but the url params are never reset?
Thanks!
You can do this:
format.html { render "path/to/new?{#meeting_with_params.to_param}" }
OR
You can use rails path helpers. You canrake routes and find your url's helper path (it looks something like this: edit_user_path, new_user_path)
format.html { render new_meeting_path(#meeting_with_params) }
As you are ok to use ajax for this checkout [https://github.com/rails/jquery-ujs](jquery-ujs), your form tag has to look something like this:
form_for #meeting, data: {remote: true} ...

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.

Parsing JSON errors using simple_form and AJAX in 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.

Rendering a partial from a controller in rails

I have a form that is adding rows to the DB via remote => true. I then want to append the new data to a table, but cannot get the correct view to render.
As of now, it is rendering the entire show.html.erb page for the new entry, but I want to layout a minimal version to be added as a . Is there a quick way to tell my controller what view to render after inserting into the db? I want to render my partial named _newly_added.html.erb
My Controller
def new
#task = Task.new
render :partial => "/tasks/newly_added", :locals => { :t => #task }
end
Thanks!!
EDIT
I think what I need is just an alternative "show" view.
I found that the method I needed to change was actually this:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
end
end
end
I just need to make an alternative show view, and then tell this to redirect_to that view.
Edited per the changes in your question. However, nothing really changes. You're thinking about things wrong, and need to adjust how you're thinking. You don't need an alternative show, you need to handle the format.js request.
The partial should be rendered within a JavaScript response, not the controller. The controller looks more like this:
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to #task, notice: 'Task was successfully created.' }
format.json { render json: #task, status: :created, location: #task }
format.js
else
format.html { render action: "new" }
format.json { render json: #task.errors, status: :unprocessable_entity }
format.js
end
end
end
Then, in views/tasks/create.js.coffee
($ '#mytable').append("<%= j render(partial: 'tasks/newly_added', locals: { t: #task }) %>")
What's going on here is that the browser makes a call to create.js. The controller responds with the create.js template, because of the respond_to block's format.js. The j escapes the contents of the _newly_added.html.erb file, and the contents of it are appended to the table. The controller doesn't interact with the existing view, instead, JavaScript is sent to the browser, and it interacts with the view.
This all changes somewhat if you're using a client-side MVC framework like Backbone or Ember, but you didn't specify that so I'm assuming you're going with stock Rails.

Resources