Rails 3.1 ajax:success handling - ajax

So Im playing with CoffeeScript, Rails 3.1 all the good stuff. I have a resource with all the usual routes index, show, create, edit, update, destroy.
The index view has a form that uses :remote => true like so:
<%= form_for #todo, :remote => true do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In the controller for create I have the following:
def create
#todo = Todo.new(params[:todo])
respond_to do |format|
if #todo.save
format.html { redirect_to #todo, notice: 'Todo was successfully created.' }
format.json { render json: #todo, status: :created, location: #todo }
format.js {render json: #todo }
else
format.html { render action: "new" }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
Im trying to not use .js.erb views as I would rather handle the JSON returned and do all the fancy appends to the todo list and so on. (It just feels cleaner to me).
In my todos.js.coffee I have used the following:
$(document).ready ->
$("#new_todo")
.bind "ajax:success", (event, data) ->
alert("Ajax SUCCESS!!!")
(Yeah just tyting to open an alert box does not work) I tried loads but just cannot trigger this event. The request does complete successfully and the new todo is added.
Any help with this would be appreciated. Thanks

Started to pour over the rails.js and wondered if any of the ajax: callbacks were being raise.
Turned out they were well the beforeSend and error... hang on... error? How could this be? The creation of the new todo happens successfully, the response is the JSON I expect. But on stepping through the callback code I notice an Invalid label error.
Quick google later brings me to this post http://blog.seqmedia.com/?p=484
Turns out the JSON is being returned as a string, Firbug got that and parsed it correctly so I could check the response. However rails.js and js in general didnt know how to handle the string and threw the above error (rather silently I may say).
The solution was in the respond_to
format.js {render json: #todo, content_type: 'text/json' }
A bit thanks to Trevor Burnham (like the book BTW) for his help and Amy from sequence media whose blog post ultimately gave me the solution.

What is #new_todo? Does an element with that ID exist? Verify that $('#new_todo').length > 0 in your code, and that it's the right element to bind your event handler to.
What is ajax:success? The jQuery API defines an ajaxSuccess event (see the Ajax Events docs), but I've never seen the version with the colon before.

Related

RAILS 4: Trying to get the current page to pass to render in an AJAX request

I have a fairly straight forward question.
On my site, within the header is a "invite a colleague" link to a modal that contains a form:
<%= simple_form_for(current_user, :url => send_invite_user_path(current_user), remote: true) do |f| %>
<%= f.label :email %><br>
<%= f.text_field :email, class: 'form-control' %>
<%= f.submit "Send", class: "btn btn-primary ShareSend" %>
<% end %>
Here is the send invite controller
def send_invite
#current_page = URI(request.referer).path
#email = params[:user][:email]
InviteWorker.perform_async(current_user.id, #email)
respond_to do |format|
flash.now[:success] = "Invite sent"
format.html { redirect_to #current_page, :current_page => #current_page}
format.js { render #current_page}
end
end
It works fine when not using AJAX, but I want to try to get it to work via AJAX. The issue is that the "current_page" when I open the modal and try to send via AJAX refers to the "send_invite" action and is looking for a "send_invite" template. I want it to render WHATEVER page the user is on. To add to my difficulty I am using friendly_id.....I tried using
#page_hash = Rails.application.routes.recognize_path(URI(request.referer).path)
To try to extract the user action from the current page path, but obviously this doesn't work with friendly id.
Is there a "Rails way" of capturing the current page (ignoring the modal) and passing this to render....
I hope this is clear...
An AJAX call does not trigger a complete reload of the current page (unless explicitly told to). The request is handled in the background by javascript.
In your case you should add a view called send_invite.js.erb (i guess in your app/views/users folder - assuming that send_invite belongs to UsersController) that has some javascript that notifies the user of a successful invite and closes the modal. This view could be as simple as:
alert("Invite sent!");window.closeMyInviteModal();
This script will be executed if (and each time) the AJAX call succeed.
Clean the js responder in send_invite. This will by default render the send_invite.js view.
format.js { }
See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example

How to pass param from 1 controller to another

I want to pass param from the following link in the view of Client controller
and the hash is #client, I want to pass #client.user_id, if i put (:id => #client.user_id) I am not able the get :id in the other controller Estate where I want to pass this param. What should I do ? Is there a way to do it ?(Two controllers are Client and Estate, I want to pass param from Client view to the Estate controllers create method. There is no nesting of resources here!)
<%= link_to "New Property", new_estate_path(:key => #client.first.user_id) %>
create action
def create
# #estate = Estate.new(params[:estate])
if current_user.Company.nil?
#estate = current_user.estates.build(params[:estate])
else
serve = User.find(params[:key])
debugger
#estate = serve.estates.build(params[:estate])
##estate.user_id = user_id
debugger
end
respond_to do |format|
if #estate.save
if #estate.Mgmt.nil?
EstateMailer.company_confirmation(#estate).deliver
end
format.html { redirect_to #estate, notice: 'Estate was successfully created.' }
format.json { render json: #estate, status: :created, location: #estate }
else
format.html { render action: "new" }
format.json { render json: #estate.errors, status: :unprocessable_entity }
end
end
end
The code you pasted here should work:
<%= link_to "New Property", new_estate_path(:id => #client.user_id) %>
I think the problem is, you are expecting the params in create method but where as it actually goes to new method.
If you are looking for the create method. You can do
<%= link_to "New Property", estates_path(:id => #client.user_id), :method => :post %>
But that is not the right approach to use for POST actions. The right solution would be to use button_to.
<%= button_to "New Property", estates_path(:id => #client.user_id), :method => :post %>
link_to defaults to GET and button_to defaults to POST, as those are their primary usages. You can override :method if you want them to perform other action than their default.
Simply do this
<%= link_to "New Property", new_estate_path(user_id: #client.user_id) %>
In your controller:
params[:user_id]
You problem is that the create action is a POST not a GET. The link_to will only allow GET actions.
I made class variable in the controller outside all the actions.
##key, and in the new action assigned ##key the user_id that was coming through the params, and this ##key in the create action. I don't know if its the right way to do it. But it worked like a charm !

Remote Form Renders as HTML instead of JS

I have a simple form:
<%= form_for [current_user, #bookcase], :id => "shelf_update_form", :remote => true, :html => { :multipart => true} do |f| %>
<input id="bookcase_image" class="file" type="file" name="bookcase[image]" size="13">
<% end %>
That automatically uploads when a file has been selected:
$("#shelf_update_form").change(function() {
$("#shelf_update_form").submit();
});
I want the update action to render js view, but by default it renders html instead. I try forcing it to render js like so:
respond_to do |format|
format.js
end
But then I get this error:
NetworkError: 406 Not Acceptable
Even then, my log reports:
Processing by BookcasesController#update as HTML
How can I get it to process as JS instead?
UPDATE:
The view:
triggerAjaxHistory("<%= #href %>", false);
I get the same results with a more generic view, too:
alert("I work now!")
In the controller, do
respond_to do |format|
format.js if request.xhr?
end
Is your view named as .js.erb?
Can you check using firebug in your browser what exactly you are getting as the response? Turn on net logging and look at the response.
Also do you have the following in your layout?
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
Can you put in logger.info whatever_message commands to make sure you the controller action executes and you go into the correct view?
What happens if you specify the js format specifically in the controller as
class UserController < ApplicationController
respond_to :js, :only => :update, :layout => 'false`
What happens if you specify the format in form_for as :format => :js
Is your form nested within another form?

Rails 3 Ajax not working

I'm new to rails and ajax so I'm experimenting by building a simple app. I created a simple to do app with User and Tasks (user has many tasks). Using Devise to handle the authentication. I set up the task CRUD and implemented best_in_place (in place editing gem) and got it to work. What I wanted to do next is add ajax create and delete following some example resources such as creating a 100% ajax CRUD. After setting up all the necessary code for the create and destroy in tasks_controller, I'm getting DELETE http://localhost:3000/tasks/26 500 (Internal Server Error) as seen in the firebug console log. These are the errors printed in the console in firebug:
DELETE http://localhost:3000/tasks/26 500 (Internal Server Error)
jQuery.ajaxTransport.send
jQuery.extend.ajax
$.rails.rails.ajax
$.rails.rails.handleRemote
(anonymous function)
jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
when the destroy link is clicked and same with create. The task got deleted and created after refresh but the ajax is just not working. I spent some time trying to figure out what's wrong but don't have any luck yet so I'm hoping I can get some help here while I keep digging into it. Below are my setups:
First the controller code:
def destroy
#task = current_user.tasks.find(params[:id])
#task.destroy
flash[:notice] = "Successfully destroyed post."
respond_to do |format|
format.html { }
format.js { }
end
end
def create
#task = current_user.tasks.build(params[:task])
respond_with(#task) do |format|
if #task.save
flash[:notice] = "Task was created successfully!"
respond_to do |format|
format.html { redirect_to tasks_url }
format.xml { render :xml => #task }
format.json { render :json => #task}
format.js
end
else
format.html { render :action => :new }
format.js
end
end
end
The task list partial to display the task list and delete
<table>
<% #tasks.each do |task| %>
<tr>
<td><%= best_in_place task, :detail %></td>
<!-- <p><%= best_in_place task, :completed, type: :checkbox %></p> -->
<td><%= link_to "Destroy", task, :confirm => 'Are you sure?', :method => :delete, :remote => true, :id=>'delete' %></td>
</tr>
<% end %>
</table>
The create form (without the other view stuff):
true) do |f| %>
<%= f.label :detail %>
<%= f.text_field :detail %>
<%= f.submit %> <% end %>
This is the javascript tag for application.html.erb (include jquery.js, jquery.ujs, application.js and other not so related js files):
Lastly I'm just trying to call an alert inside destroy.js.erb and with create.js.erb:
alert("Task was deleted");
Again, the crud is working normally when refreshed, it feels like the destroy.js.erb and create.js.erb is not linked somehow. I appreciated if you can provide a few hints.
Here is the error from the console after hitting delete:
ActionView::Template::Error (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each):
1:
2: <table>
3: <% #tasks.each do |task| %>
4:
5: <tr>
6: <td><%= best_in_place task, :detail %></td>
app/views/tasks/_tasks.html.erb:3:in `_app_views_tasks__tasks_html_erb___1747031968745406293_70257861453000'
app/views/tasks/destroy.js.erb:4:in `_app_views_tasks_destroy_js_erb___3673072470672404292_70257861472560'
It looks as though you have a syntax error in the destroy action. I think you're missing an end for the respond_to block.

link_to remote=>true not updating with ajax

Using rails3 and prototype (rails.js)
I have a simple list of products with edit and delete links as images.
When deleting a product, the list is not updated. Refreshing the page shows that the product has indeed been deleted.
/app/views/products/list.rhtml
<div id="product_list">
<%= render :partial => 'list' %>
</div>
/app/views/products/_list.rhtml
<%= link_to image_tag("delete.png"), { :controller => 'products', :action => 'destroy', :id => product }, :method => :delete, :confirm => "Are you sure?", :remote => true %>
/app/controllers/products.rb
def destroy
Product.find(params[:id]).destroy
#products = Product.all
end
/app/views/products/destroy.rjs (not sure what to do with that...)
$(document).ready(function() {
$("#product_list").html("<%= escape_javascript( render(:partial => "list") ) %>");
});
So the remote link seems to work fine.
I'm not sure how to use the ajax callback to update #product_list
I tried to put the following in the head of the page:
$(document).ready(function(){
$('#product_list').bind("ajax:success", function(evt, data, status, xhr){
alert('hello');
})
});
But it's not executed (that's probably not a valid code for prototype) and I wouldn't know anyway what code to put inside so that my list gets updated after destroying a product
Any help (other than "use jQuery") is greatly appreciated!
EDIT: Here is the server log for the delete action (after I moved the javascript above to destroy.js.erb)
Started POST "/products/destroy/3" for 127.0.0.1 at .....
Processing by ProductsController#destroy as JS
Parameters: {"_"=>"", "id"=>"3"}
[1m[36mProduct Load (0.0ms)[0m [1mSELECT `products`.* FROM `products` WHERE (`products`.`id` = 3) LIMIT 1[0m
[1m[35mSQL (0.0ms)[0m BEGIN
[1m[36mSQL (0.0ms)[0m [1mDELETE FROM `products` WHERE (`products`.`id` = 3)[0m
[1m[35mSQL (78.1ms)[0m COMMIT
[1m[36mProduct Load (0.0ms)[0m [1mSELECT `products`.* FROM `products`[0m
Rendered products/destroy.js.erb within layouts/standard (31.2ms)
Completed 200 OK in 312ms (Views: 62.5ms | ActiveRecord: 78.1ms)
Processing by ProductsController#destroy as JS so the remote link works
[36mProduct Load (0.0ms)[0m [1mSELECT products. FROM products* The #products = Product.all is executed
Rendered products/destroy.js.erb within layouts/standard the javascript fie is rendered
So now I guess it's a problem with the javascript code:
$(document).ready(function() {
$("#product_list").html("<%= escape_javascript( render(:partial => "list") ) %>");
});
Is that kind of code supported by prototype? I don't use jQuery...
Found the answer on my own:
/app/controllers/products.rb
def destroy
Product.find(params[:id]).destroy
#products = Product.all
respond_to do |format|
format.js { render :layout=>false }
end
end
/app/views/products/destroy.js.erb
$("product_list").update("<%= escape_javascript(render(:partial => "list")) %>");
Why is there NO tutorial, code example or anything clear about the ajax thingy in rails3?
I had to use code parts from 5 different blogs, forums and casts, and mix them all together until I find the right combination... sigh
on repecmps lines,
just insert :content_type to represent part of content downloaded, like this:
format.js { render :layout=>false, :content_type => 'application/javascript' }
with complete part of repecmps responses:
def destroy
Product.find(params[:id]).destroy
#products = Product.all
respond_to do |format|
format.js { render :layout=>false, :content_type => 'application/javascript' }
end
end
/app/views/products/destroy.js.erb:
$("product_list").html("<%= escape_javascript(render(:partial => "list")) %>");
and, I found this to night.
I think your destroy action is doing too much, as it is destroying the product and list all the products. You could do something like:
/app/controllers/products.rb
class ProductsController < ApplicationController
respond_to :html, :js
def destroy
#product_id = params[:id]
Product.find(#product_id).destroy
respond_with do |format|
format.html { redirect_to posts_path }
end
end
end
/app/views/products/destroy.js.erb
$("#product_<%= #product_id %>").remove()
As long as your product element in the index uses something like dom_id, here's an example:
<ul id="products">
<% #products.each do |product|
<li id=<%= dom_id product %>>...</li>
<% end %>
</ul>
This way your destroy action will only destroy the intended product, and if the client has no JS it fallback the HTML request which will redirect to the products index which will be updated accordingly.
Hum... I'm going to try to help you.
Are you sure after clicking on the delete link, the request is handled as JS ?
Check on the log.
Is you file "app/views/products/destroy.rjs" is rendered ?
Rjs doesn't exist anymore in rails3. The new name is UJS.
Try to rename the file to destroy.js.{haml or erb}
Is it better ?

Resources