Rails 3 - AJAX, response JS - How to Handle Errors - ruby-on-rails

Given the following controller:
def create
if #mymodel.save
format.js
else
format.js { render :js => #mymodel.errors }
end
end
What's the Rails way of handling a .JS error response... Do I create .js file with a different file name just for servering Errors?
Do I add an IF ELSE in the .js file?
thanks

It's been a while since this question was posted - but I just spent a while figuring this out & couldn't find too much help on this online, so:
The solution is to create .js.erb files - one for success and one for failure.
def create
#foo = Foo.new(params[:foo])
if #foo.save
respond_to do |format|
format.html { redirect_to root_path }
format.js { render :action => "success"} #rails now looks for success.js.erb
end
else
respond_to do |format|
format.html { render :action => 'new'}
format.js { render :action => "failure"} #rails now looks for failure.js.erb
end
end
end
end
If seems that if you don't specify a file name, rails will look for create.js.erb in both cases (because format.js is called from create). This is not great in the case of success/error situations because you want different behaviour for each scenario - so override the filenames through the :action attribute.

Related

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

Rails 4 - Why Can't I Redirect After Save?

I am uploading several images (from http://localhost:3000/choices/new), which work fine, however, I am trying to redirect back to: http://localhost:3000/choices after it saves.
Here is my controller:
#app/controllers/choices_controller.rb
def create
#choice = Choice.new(choice_params)
#choice.filename = params[:filename].titleize
if #choice.save
respond_to do |format|
format.html { redirect_to choices_path }
format.json { head :no_content }
end
end
end
In Rails Console, it outputs:
Redirected to http://localhost:3000/choices
Completed 302 Found in 58ms (ActiveRecord: 52.8ms)
Yet, the "new" page remains static. Any idea on how to correctly redirect this, perhaps with a flash message saying "Images uploaded succesfully"?
Thanks very much!
I only just learnt what asynchronous requests are, so I hope this helps...
If you're sending a 'background' request with JS, how can the controller affect your browser's viewport?
The controller is server-side, and is loaded every time you send a request. This means that unless your actual browser made an HTTP request directly to the controller, how can it cause a change in the view you have already rendered?
JS is client-side technology, which means that it can cause things to happen on your behalf, but its scope is limited to taking "DOM" elements & interacting with them.
I looked at some pretty informative answers in this regard, and found these ideas:
Rails 3.2.0 - Redirecting after a JSON call is made
Rails 3: How to "redirect_to" in Ajax call?
https://www.ruby-forum.com/topic/206571
All of these answers say a similar thing: you need to handle the redirect with JS
Why not do something like this:
#app/controllers/choices_controller.rb
def create
#choice = Choice.new(choice_params)
#choice.filename = params[:filename].titleize
if #choice.save
respond_to do |format|
format.html { redirect_to choices_path }
format.json { render :json => {
:location => url_for(:controller => 'choices', :action => 'index'),
:flash => {:notice => "File Uploaded!"}
}
end
end
end
#assets/javascripts
$(document).ready(function() {
$.ajax({
success: function(data) {
window.location = data.location
}
})
});
A much cleaner way to do it will be to send a plain JS request, and have this:
#/views/new.js.erb
window.location = <%= choices_path %>
#app/controllers/choices_controller.rb
def create
#choice = Choice.new(choice_params)
#choice.filename = params[:filename].titleize
if #choice.save
respond_to do |format|
format.html { redirect_to choices_path }
format.js
end
end
end
This i similar to the above answer, but a little more versatile. It took some playing but I finally got it working, and I signed up for StackOverflow just so I could post an answer. Here is my solution (though I was using JS as my format)
respond_to do |format|
format.html { redirect_to choices_path }
#path = url_for(:controller => 'choices', :action => 'index')
- or - choices_path for a named route
format.js { render 'shared/redirect'}
:flash => {:notice => "File Uploaded!"}
end
Now in your shared/redirect.js.erb file (notice this is a shared file, so you can reuse it):
#shared/redirect.js.erb
window.location.href = '<%= #path %>';

How do you respond_to another js file in the controller using Ruby on Rails?

I basically have an action that because of logic needs to return with the contents of another js file. How do I go about doing this? Thanks
app/controllers/classrooms_controller.rb
def create
if params[:test_logic]
respond_to do |format|
format.js { render 'create_differently' } # This doesn't work.
end
else
redirect_to root_path
end
end
app/views/classrooms/create_differently.js.erb
alert('hi')
You need to add
:layout => false
to avoid the rendering of the html layout for your js file.
Additionally you could define the different js-file like this
:template => "classrooms/create_differently.js.erb"
both together:
format.js {
render :template => "classrooms/create_differently.js.erb",
:layout => false
}
For browser-based testing, please be aware calling js not html!

rails respond_to format.js API

I am an experienced JAVA and C++ developer and I am trying to understand how rails works.
I got this code below:
respond_to do |format|
if #line_item.save
format.html { redirect_to store_url }
format.js { render :json => #line_item, :mime_type => Mime::Type.lookup('application/json'),
:callback => 'javascriptFunction' }
and I've been searching the api that defines what I can pass inside the format.js {} but I could not find..
first of all: what kind of statement is format.js, is that a variable?
and most important: what attributes can I pass into format.js {} ? can you pass the direct link? I've searched over the http://api.rubyonrails.org/
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end
js here specifies a mime-type that the controller method would send back as a response;
Default Rails mime-types.
If you try also with format.yaml:
respond_to do |format|
format.js
format.yaml
end
that will mean that your controller will return yml or js depending on what the client-side is asking;
{} in terms of ruby is a block;
If you don't specify any rails will try to render a default file from app/views/[contoller name]/[controller method name].[html/js/...]
# app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
will look for /app/views/some/hello.js.erb; // at least in Rails v. 2.3.
If you do specify block:
respond_to do |format|
# that will mean to send a javascript code to client-side;
format.js { render
# raw javascript to be executed on client-side
"alert('Hello Rails');",
# send HTTP response code on header
:status => 404, # page not found
# load /app/views/your-controller/different_action.js.erb
:action => "different_action",
# send json file with #line_item variable as json
:json => #line_item,
:file => filename,
:text => "OK",
# the :location option to set the HTTP Location header
:location => path_to_controller_method_url(argument)
}
end
I believe this was the url you were looking for:
https://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to
This might also be helpful to some, to see that you can actually render js directly within the format.js method, if you for example only have a small one line js statement you want to return, and you don't want to defer to a RJS file like controller_action_name.js.erb:
respond_to do |format|
format.html { redirect_to new_admin_session_path }
format.js { render :js => "window.location='#{ new_admin_session_path }'" }
end

pass two instance variables to js.erb files?

I need to pass two instance variables to a javascript file that is being used by an ajax request to update a user display. This is what I need to do:
respond_to do |format|
if #post.save
format.js { #post #user_vote } # <-- right here
else
format.html { redirect_to :back, :alert => 'There was an error in removing the vote' }
end
end
How is this done?
There is no need to pass the instance variables if you use js.erb files. You can directly put the rails tag and access those variables inside the js.erb file
Eg:
In your controller just put
format.js #instead of format.js { #post #user_vote }
and in js.erb file you can access the instance variable as
$('#ele').html("<%= #post.name %>");
The instance variables in your ActionController action are available in your views automagically. E.g. your controller:
# posts_controller.rb
def update
# Your implementation here
#post = ...
#user_vote = ...
respond_to do |format|
if #post.save
format.js
format.html { redirect_to post_path(#post) }
else
format.js { ... }
format.html { redirect_to :back, ... }
end
end
end
Then in your update.js.erb:
# update.js.erb
console.log('Post: <%= #post.inspect %>');
console.log('User vote: <%= #user_vote %>');
# Your JS implementation here
(Also I noticed your logic in the respond_to block is probably going to cause problems. You should render both js and html formats for both success and failure conditions of #post.save.)

Resources