:remote => true with url_for, How does one do this? - ruby-on-rails

I am trying to make an entire div tag clickable. The code I am trying to use is below, and when I add the
:remote => true
bit it throws Too many args error, 2 for 1.
Code:
<div id="foo" onclick="window.location = '<%= url_for foo_controller_path(:someparam => #left), :remote => true %>'"></div>

url_for doesn't accept the :remote => true argument, it's usually the link_to method that you would send it to.
Is there a reason you can't make your <div> a link instead? For all intents and purposes it is functioning as a link, so you should mark it up as such, we call that semantic mark-up.
If you really wanted to do this it would probably be best to use jquery (or prototype, if that's your cup of tea) to perform the action unobtrusively... it makes it easier to do the ajax request too. Are you trying to update something on your page after the link is clicked, or just do nothing?
Also the 'window.location' is telling the javascript on the page to redirect. You wouldn't use that if you wanted to make the request remotely.
Using jquery you could do it like this if you want to stick with a div
%(function(){
$('#foo').click(function(){
$.get(
url: $(this).data('request-path'),
success: function(data){
alert('success sir! controller responded with ' + data);
}
);
});
});
And use this in your view:
<div id='foo' data-request-path='<%= url_for foo_controller_path(:someparam => #left) %>'></div>
But if you changed it to a link tag you could do this instead...
= link_to("", url_for(foo_controller_path(:someparam => #left)), :remote => true, :id => 'foo')
And it ought to just work. Then you can style this link the way that you were trying to style your div tag.
This is more semantic and less code for you to worry about. If you need to update something in the dom afterwards you can add this jquery (if you're using jquery, and rails3):
$('#foo').bind('ajax:success', function(data){
alert('successful request! data was: ' + data);
});
I didn't necessarily test all of this but it should be a good starting point... I'm not a big fan of putting onclick handlers into tags. It tends to work nicer when you bind events using jquery.
If you want to be able to do what i've described but you're in rails 2, you can get the rails3 jquery script from here: https://github.com/rails/jquery-ujs
Note that you'll also need that script if you're using rails 3 and want jquery instead of prototype (like me!). Rails 3.1 will come bundled with jquery instead of prototype I hear, by default.
And change the :remote => true in that url_for to "data-remote" => true (for rails 2, with rails 3 you can use the symbol syntax and it makes the 'data-remote' attribute for you.
Let me know if something didn't quite work or you need clarification. Or even if you hate my ideas alltogether :p

Related

Rails - how can I create an ajax link for row highlighting

I have a great example of instant row hilighting that I want to do:
http://www.mrc-productivity.com/techblog/?p=684
How can I create a Turn on row highlights link with rails.
I have tried many combination of link_to and button_to with :remote => true but I can't get the syntax right and everything seems to end up with a regular link.
At the end of the day I am trying to turn on and off row table highlighting as in:
html:
Turn on row highlights
jquery:
$(document).ready(function() {
$("a.on").click(function(){
$("tr:nth-child(odd)").addClass("two");
$("tr:nth-child(even)").addClass("one");
event.preventDefault();
});
$("a.off").click(function(){
$("tr:nth-child(odd)").removeClass("two");
$("tr:nth-child(even)").removeClass("one");
});
});
You can easily create a link like that with:
link_to('Turn on row highlights', '#', :class => 'on')
In this case, you don't need to use the Rails helpers at all. You can simply use that link tag directly in an erb file:
Turn on row highlights
or for HAML:
%a.on{href: '#'} Turn on row highlights
The Rails view helper are only useful when you're linking to a Rails resource. The remote: true option is used when you want to unobtrusively access a resource with AJAX. Neither apply in your case.

Rails UJS link_to :remote does AJAX GET and normal <a href> GET

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'

How to upgrade the :update=>'div_id' option of remote_form_for from Rails 2 to Rails 3?

I can't figure out how to upgrade this code from Rails 2 to Rails 3:
<% remote_form_for(item, :update => 'div_id') do |f| %>
...
I tried this:
<%= form_for :item, :remote => true, :url => { :controller => "items", :action => "create" }, :update => 'div_id' do |f| %>
...
It creates the new item but it fails in updating the content within <div id="div_id"></div> tags. It seems Rails 3 no longer supports the ":update" option for a remote form_for. Any suggestion?
You could use RJS, but that's being deprecated too (and for good reason). The simplified, best-practices way to handle this in Rails 3+ is as follows (assuming jQuery):
# your_view.html.erb
<div id="receiver-id"></div>
<%= form_for :some_model, :remote => true, :id => 'form-id' do |f| %>
...
<% end %>
# application.js (or any other .js loaded on the page)
$(function(){
$('#form-id').bind('ajax:success', function(xhr, data, status){
$('#receiver-id').html(data);
});
});
The ajax:success hook gets called by the jquery-ujs (aka jquery-rails, aka rails-ujs) remote link/form handler. See for yourself. There are lots of other callbacks/hooks available for you to use, too. If you wanted to make this even more flexible, you could use live instead of bind, and bind to a class that dictates where the ouput goes (e.g. "sidebar") and then all remote links/forms with the sidebar class would have their HTML response go to div#sidebar.
The most straightforward way to do this would be to write a javascript view template, e.g. create.js.erb which would look something like this:
$('#div_id').html("<%= escape_javascript(render(#item)) %>");
(depending on your setup, of course, I'm assuming an #item variable and an associated _item partial)
Edit:
coreyward is right. This is the RJS way which is more of the old fashioned Rails 2.x "Rails way". It's probably more familiar, but has issues. Your specific case is one of them, actually, as typically you might bind to an HTML element to update using the record's id (e.g. div #item_1), and in the create case there is no id available beforehand, complicating matters.
Binding via clientside JS eliminates this issue. RJS works in something of a vacuum, making assumptions about the state of the client's HTML and having no access to it.
I know the question is old but I when migrating to Rails 3 I found a pretty good way of doing this, so I thought I would post it here in case anyone else is in a similar solution.
In layouts/update_page.js.erb I put this file:
$j('#<%=#update_div_id||"list_div"%>').html('<%= escape_javascript render(:partial => (#partial_div||"index"), :locals => #local_hash) %>');
This is mainly used for searches that use remote, so in the index action in the controller, I just added the following code.
respond_to do |format|
format.html
format.js {render 'layouts/update_page'}
end
Since remote is being used, it will always try to use javascript first, so it will render the update_page.js.erb file from above. For us, we almost always use the div#list_div on our index pages, so we update that by the default, however if you need to update something different, you can pass in #update_div_id, and if you need to render a different page, you can pass in #partial_div.
To clarify, for a lot of things, it is probably better practice to use the callbacks, but I found this to be a much easier way, when we had to migrate over nearly 100 of these calls.

Rails 3: How to make an Ajax call?

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/

Ruby on Rails3: How do I invoke javascript before an ajax event is fired with remote => true?

<%= link_to( {:controller => 'board',
:action => 'take_turn',
:id => #board.id,
:x => col,
:y => row} , :remote => true, :onClick => "return links_disabled;") do %>
<div class="ttt_square">
</div>
<% end %>
in rails2, there were :before, and :complete params, but I have not found any documentation for this in rails3
As I understand it, this is one of the consequences of Rails 3 using UJS (unobstrusive javascript). Rails 3 enables you to keep the javascript away from e.g. a link-tag. Instead of the link-tag specifying what should be done via javascript, you make the javascript observe the link-tag.
You achieve this by binding a function to a certain event of an object, eg. binding the ajax:before event of the link-tag to a function.
In this blog post the author explains how to do it, in his case with JQuery.
As far as I understand, in Rails 3 you bind the callback events to the element on the client side, and they are fired by rails.js at the appropriate times.
$('#myform').bind('ajax:success', function(){
alert('I succeeded');
})
If I remember well, there is no more support in Rails3.
You could use native jQuery function:
ajaxStart()
http://api.jquery.com/ajaxStart/
See details here: http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/
My version (jquery-rails 0.2.6) supports ajax:before, loading, success, complete, failure, and after. The parameters to the success/failure functions are not the same which has tripped me up in the past. But the following works for me:
$('a').bind('ajax:loading', function() {
alert('here');
});
If your link element was created after the initial page load, you might need to bind using 'live':
$('a').live('ajax:loading', function() { alert('...'); });
I would also double-check that your onclick handler is not interfering.

Resources