I want to execute a simple thing. When the user clicks the link jQuery needs to generate an Ajax request which sends the id of the link item to a method in the controller. Basically I want a nice looking modal dialog window when the user clicks the delete link. That window needs to contain various info about the deleted items.
E.g.
<%= link_to "Delete", item, :id => "delete" %>
I'm able to select this link with jquery and even to open a popup dialog when the user clicks it. Through application.js but what i really need is jQuery to call my method when the link is clicked and in my method I would answer via format.js. In the js file I place the code to show modal dialog with required parameters. All those actions asynchonous via ajax ofcourse.
I can't generate the ajax request to the method in the controller. Don't know already how to deal with the jQuery.ajax method, especially how to force jQuery to pass the url parameter to the rails method. I watched the railscast and studied the example with .post, but I don't need to submit any form.
Any advise is appreciated.
Thanks
Rails expects a post, with a hidden param.
$('#delete').click(function(e){
e.preventDefault();
$.post($(this).attr('href'), { _method: 'delete' });
});
Rails 3 has an unobtrusive way of doing this using a jQuery plugin:
http://github.com/rails/jquery-ujs
Once you have that loaded into your layout (with jQuery 1.4.1 or newer), you can do interactions like this pretty easily.
<%= link_to 'delete', item, :remote => true, :method => :delete,
:confirm => 'Are you sure?' %>
In Rails 3 all this does is add some HTML attributes to your link. These get caught by live handlers in the jQuery plugin. It's easy to use this behavior in a Rails 2 application, though:
<%= link_to 'delete', item, :'data-remote' => true, :'data-method' => :delete,
:'data-confirm' => 'Are you sure?' %>
Note that you need to have the jQuery plugin loaded in your view.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
If you need the initial response to be a modal instead of an alert, you could make the first link a bit simpler:
<%= link_to 'delete', modal_confirm_item_url(item), :'data-remote' => true %>
You could link it to some pre-existing member action. Or since you may eventually want to use .js responses from those actions to serve other ajax requests, it may make sense to create a new action to handle this behavior.
Related
I've made a Rails app using UJS and remote=true links.
For a controller#index action, instead of showing the content on page load, I'd like to call the #index action via Javascript once the page has loaded.
In short, I want to trigger the same functionality that is carried out when clicking a link like this:
<%= link_to "My Link", index_controller_action, :remote => true %>
But I want this to happen on 'page ready' rather than having to click the link.
Should I use the JQuery $ajax function for this? I have hacked it for now by triggering a false 'click' action on the remote link, but I'm sure this isn't best practice...
I have an application, which contains calls. I want to be able to cancel the call and supply a reason for the call cancellation. So far I have my cancel action working in the controller, but I'm trying to figure out how to expand it so before it posts "cancel" to the call_status field it will also populate a cancel_reason field based on a drop down.
Here's what I have so far:
view code: cancel button
<%= link_to 'Cancel',
cancel_call_path(call),
confirm: 'Are you sure you want to cancel the call?',
:method => :post,
:class => 'btn btn-danger btn-mini' %>
controller code: cancel action
def cancel
#call = Call.find(params[:id])
attrs = {
call_status: 'cancel',
incharge_id: #call.units.first.incharge_id,
attendant_id: #call.units.first.attendant_id
}
attrs.merge!({ incharge2_id: #call.units.second.incharge_id, attendant2_id: #call.units.second.attendant_id }) if #call.units.count == 2
if #call.update_attributes(attrs)
#call.units.each do |unit|
CallMailer.cancel_call(unit.incharge, #call).deliver
CallMailer.cancel_call(unit.attendant, #call).deliver
end
redirect_to calls_url, :notice => "Call was successfully cancelled"
else
redirect_to calls_url, :error => "Whoops."
end
end
I want either the confirmation pop-up shown, with the reason for cancellation, or the cancel action tied to a different view with a small form, that includes a reason.
By default the confirm attribute in link_to uses a JavaScript window.confirm which is a simple yes/no that returns true/false.
If you want to do it all on the same page you You'll need to use JavaScript and Ajax to accomplish this. Something along the lines of adding an event handler on the Cancel link that will show a modal with a drop down. The result of this modal will then Ajax a POST request to the Rails app. There are a lot of jQuery Plugins that you can use to help you accomplish this in Rails.
The second option is the one you described which would be to use a separate action in your controller. In terms of UX I think the first option is a better route to go and isn't as scary as it sounds.
EDIT:
In addition to the helpful comments below, two excellent articles by Steve Schwartz explain everything clearly:
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
http://www.alfajango.com/blog/rails-3-remote-links-and-forms-data-type-with-jquery/
Rails 3.2.2 / jquery-rails 2.0.1 (uses jquery 1.7.1)
I have link which sends an AJAX request to add additional file upload fields to a form. Everything page-related works correctly - the new form field HTML fragment is retrieved from the server and appended to a div inside the form.
However,
The server receives two GET requests. One is the AJAX request ; the other appears to be the "normal" anchor element GET. I expected the "normal" GET would be stopped by Rails UJS.
Am I supposed to disable the normal link action myself? Can someone please explain what I have misunderstood, and what I should be doing instead [to prevent the second request]?
I've seen this question: Rails 3 UJS - controller gets called twice by link_to :remote. Accordingly, I tried changing the asset pipeline compilation config.assets.debug = false, but it had no effect. Moreover, this is not a double-AJAX GET request, so I think it's a different issue.
Thanks for any help!
Server log snippet:
Started GET "/files/new?asset_number=2" for 127.0.0.1 at 2012-03-23 15:23:27 +0100
Started GET "/files/new" for 127.0.0.1 at 2012-03-23 15:23:27 +0100
Browser HTML:
Add another file
View:
<%= link_to 'Add another file', new_file_path, :remote => true,
:update => 'files',
:position => 'after',
:id => 'add_another_file' %>
Controller's coffeescript:
$( ->
$('a#add_another_file').click( ->
url = '/files/new?asset_number=' + $('#files input').length
$.get(url, ((data) -> $('#files').append(data)), 'html')))
If you're adding a click event to a#add_another_file , then you don't need to use :remote => true , because you're making the Ajax request manually.
Also, the click event should prevent the default action from occurring. This can be accomplished by adding event.preventDefault(); to the beginning of the click event's callback. Note that the callback needs to accept the event argument.
If you want to use the :remote => true option, you should remove the custom click event that you've added. This is because the :remote => true option tells the *jquery_ujs* library to hijack clicks on a#add_another_file. Thus, you needn't make your own HTTP request.
Next, to dictate what's done with the response, bind to the various events that will occur on a#add_another_file, such as success and error.
Here's the full list of Ajax events that you can bind to.
It's actually pretty simple, your remote link_to is sending one request (without params) and you've added a click event on that link to send another one (with params).
You should simplify your link_to as:
<%= link_to 'Add another file', new_file_path, :id => 'add_another_file' %>
Then in your click event you should return false so it doesn't follow the url.
It looks like you're using a lot of unnecessary parentheses in your coffeescript.
$ ->
$('a#add_another_file').click ->
url = '/files/new?asset_number=' + $('#files input').length
$.get url, ((data) -> $('#files').append(data)), 'html'
Is there a simple RESTful way to have a fallback url for the link_to with :method => :delete that will work for folks who have javascript disabled?
For example, suppose I have a list of comments. To add a link to delete a comment, I might put:
<%= link_to "Delete", comment_path(comment.id), :method => :delete %>
This would produce a link with the data-method="delete" that my ujs driver (jquery_ujs in my case) will turn into a DELETE request. However, when javascript is turned off, the link is followed as a GET request (as advertised in the docs), and my controller gets rightfully confused.
Is there a good and simple way to resolve this problem? There's Railscast 77, which shows one solution, but this seems to require an awful lot of extra code and throws out the quite elegant :method => :delete solution. I'd be OK with it producing a link to a confirm-delete page when javascript is disabled.
The only solution I can think of is to use button_to on the page and UJS to replace it with the corresponding link_to. This somehow doesn't seem quite right to me, but maybe it's OK? Any other ideas?
Personally i don't like the idea of mapping the :delete to a :get, it's not RESTFul...The solution i use is the same than the one you have been thinking about, ie a button_to instead of the link_to, and if needed i can use CSS to style the button so that it looks like a link.
I would like to have a link (is there a better option?) on my page which will make an Ajax request when clicked. (I would like to update a field in my database when the link is clicked.)
What is the simplest way to achieve this ?
Could you refer me to some tutorials ?
Really simple. In your view, have a link/button like so. Important bit being :remote => true
<%= link_to 'Update Thingy', update_thingy_path, :confirm => 'You sure you wanna update?', :remote => true %>
or
<%= button_to('Update Thingy', {:action => 'update_thingy', :thingyid => 314}, :method => :get, :remote => true) %>
Obviously, you have to get update_thingy_path to resolve to some action as normal. The difference is when you render you are going to be rendering some *.js.erb instead of *.html.erb. In that update_thingy.js.erb, you just put whatever javascript you want to run in the client. You might wanna notify the user that the update happened for example (in jQuery):
$('#notice').html("Thingy was update.")
Or if whatever javascript you're returning is really simple, in the controller you can do something like the following instead of having a whole js.erb for a one-liner.
render :js => "alert('Blah')"
You're really going to be using two technologies to accomplish this: javascript on the client-side, and rails on the server-side.
The general idea is that you want to:
(1) add your web methods on the server side with rails, and then
(2) use something like jQuery to get your client-side js calls up to the server to fire off the web methods.
Two writeups I found by googling for : rails3 ajax
http://www.stjhimy.com/posts/7-creating-a-100-ajax-crud-using-rails-3-and-unobtrusive-javascript
http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/
API Reference for using jQuery's ajax post() method:
http://api.jquery.com/jQuery.post/