Rails: rendering the js.erb template using the controller - ruby-on-rails

I have a rails app trying to incorporate some AJAX where clicking new opens a modal window and a form. I want to be able to display the validation errors if it fails so in my create action, i thought about re-rendering the new.js.erb file. Is this the right approach?
def create
#place = Place.new(params[:place])
if #place.save
redirect_to places_path, :notice => "Successfully created place"
else
render "new.js.erb"
end
end
The result I get is escaped js text in my browser like:
$("#new_grouping").html("<div class=\"modal-header\">\n <a class=\"close\" data- dismiss=\"modal\">×<\/a>\n <h3>Create a new menu section<\/h3>\n<\/div>\n<form accept-charset=\"UTF-8\" action=\"/places/1-mama-s-pizza/groupings\" class=\"simple_form new_grouping\" id=\"new_grouping\" method=\"post\" novalidate=\"novalidate\">
I've tried putting various options into the render block but no luck. Any tips?

The best practice would be to support both, AJAX and Non-AJAX calls, in case the user has javascript turned off for any reason.
def create
#place = Place.new(params[:place])
respond_to do |format|
if #place.save
format.html { redirect_to places_path, :notice => "Successfully created place" }
format.js # renders create.js.erb, which could be used to redirect via javascript
else
format.html { render :action => 'new' }
format.js { render :action => 'new' }
end
end
end
The render :action => 'new' actually renders the template of the controller action new which results to new.html.erb respectively to new.js.erb depending if it's a non-AJAX or an AJAX call.
In new.js.erb goes your ERB/javascript code:
$("#new_grouping").html("<%= escape_javascript(...) %>">

As i know, rendering partial in controller is a bad idea, because then response can be without content-type and some browsers can't understand this. if it is some file attached to action you should write
render :action => "create"
or if you need just render a singe partial then in your action file write
<%= render :partial => "path/to/partial" %>
as i said, then you won't have problems with content-type in response

Related

Rails flash message after AJAX success

I have to ask about something that probably no one uses anymore. I want to display flash[:notice] after successfully AJAX action. I'm aware of this and that one and even this gist but none of them fit my example:
#controller code
def new
#registrant = Registrant.new
respond_to do |format|
format.html
if params[:add_patient_to_caregiver]
format.js { render partial: 'add_patient_to_caregiver' }
end
end
end
#view triggered controller#new action via AJAX
<%= link_to 'Add Patient to Caregiver', patient_to_caregiver_path(add_patient_to_caregiver: true, patient_to_caregiver: registrant.id), method: :get, remote: true %>
I want to have something like format.js { render partial: 'add_patient_to_caregiver', flash[:notice] = 'Patient Added' } to display it in a view. I've come up with a workaround:
_add_patient_to_caregiver.js.erb
$("#add-patient").html("<%= escape_javascript(render :partial => 'registrants/add_patient') %>");
$("#flash-messages").after("<div class='alert alert-success'> Patient Added </div>");
And flash message shows up but there are no close button there. Is there any better way to do so? or how to add close button to that message so that the whole page doesn't reload when it is pressed?

How do I change the render file path for AJAX call

I'm running Rails 2.3.8 and I have a respond_to in my Projects controller create action.
def create
respond_to do |format|
format.html { redirect_to('/') }
format.json :status => 200
end
end
I have an AJAX call to this action. The Rails application then renders
projectdocs/create.erb
My question is, how can I change this file path within my action from create.erb to create.erb.js.
I think your controller-name would be "projectdocs" an not "Project" if he renders "projectdocs/create.erb", but that's not the point.
You can explicit render a js-file using
format.js { render :action => 'create' }
if this Format is requested.
It depends on called format. If client wants js, add format.js and rails will try to render first of all create.js.erb

.js.erb file available to all other views?

So, in my rails app I ajaxified the error messages on one of my pages. the process was (so everyone understands) first, in my 'edit' link_to I added :remote => true at the end of it thus having it send an ajax request. I then added the line format.js in my respond_to do |format| block. Then, I made an edit.js.erb file with the following line of code $('#error').html("<%= flash[:error] %>"); which basically finds the error div in the current page and replaces the html in that div with the error flash message. This is cool right? No more annoying page refreshes in the event of an error.
Question is, I want to do this for all my edit and destroy pages, but how without making an edit.js.erb and destroy.js.erb file for each view folder? seems pretty simple, and maybe im just missing an obvious answer because I'm exhausted, but I can't figure it out... so... help?????
EDIT!
this is my edit controller
def edit
user = User.find(session[:id])
#table = Table.find(params[:id])
if user.id != #table.created_by
flash[:error] = "ERROR"
respond_to do |format|
format.js {render :template => 'shared/show_error'}
format.html
end
else
flash[:error] = ""
respond_to do |format|
format.js {render :template => 'table/edit', :formats => :html}
format.html
end
end
end
Problem now is, it works fine for showing the errors but if there are no errors it doesnt action render the edit page... In the server window it shows it did, but it doesnt actually show on the screen... Any ideas?
I would suggest you then make a general JS.erb file, something like:
# app/views/shared/show_errors.js.erb
('#error').html("<%= flash[:error] %>");
And then in your controller action, or from another JS.erb file, just type:
render :template => "shared/show_errors"
And voila!
I actually fixed my own problem by accident... I removed the line {render :template => 'table/edit', :formats => :html} from the else block.

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);
});
}

Rails validation conditional redirect

I am currently having an issue with how Rails is performing and responding to a validation result. I have a user registration form. The user could hit this form in two different places. They could hit the form from the homepage or from users/new. Both forms will post to the same place as I am trying to keep it DRY.
The users/new page works as is expected. If the user has a validation issue it will return and populate the form. Where I get a problem is on the home page. If a user has a validation issue it now redirects to the users/new page. I would much prefer that when on the home page I would return the user to that same page and show the validation results there. Is there a way in the controller to redirect to the form the user was at?
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to(#user, :notice => 'User was successfully created.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" } # I'm thinking I can do something here?
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
I have tried to change the render :action => 'new' line to redirect to the user url but it hasn't worked. Is there something I'm missing?
First, I would add querystring parameters to the URL it is posting to with the controller and action that it came from with something like this:
# Using form_tag
<%= form_tag user_path(#user, :controller_name => controller.controller_name, :action_name => controller.action_name) do %>
# Using form_for
<%= form_for #user, :url => user_path(#user, :controller_name => controller.controller_name, :action_name => controller.action_name) do %>
Then, you can update that line in the create action of your controller like this:
render '#{params[:controller_name]}/#{params[:action_name]}'
Update
I just realized that using the code above, will render the correct view the first time validation fails, but if validation fails a second time, it will try to render the users/create view. If this is the route you want to take, you should not use controller.controller_name, etc in the view, but assign #controller_name correctly and use that variable instead. However, this only adds to the 'overkill' comment made by Xavier.
Art's on the right track, but you can't use a redirect, as you need the instance variable #user that's set in your controller, which'll be lost on a new HTTP request (because ever request is handled by a new, clean controller instance).
But you can use the referer information yourself, and use that to pick the right page to render:
render :action => (request.referer =~ /\/users\/new/)? :new : :index
Note: Another answer popped up while I was posting that suggests adding the old controller / action fields to your form, but that seems like overkill to me - you already have all the information you need in request.referer.
Hope that helps!
Try redirect_to :back
It's a shorthand for redirect_to(request.env["HTTP_REFERER"])
oops, it only works for success. sorry
well, then you have to check inside the block (after format.html) where he came from (by looking at request.env["HTTP_REFERER"]) and render respective action.

Resources