Rails 3 UJS - controller gets called twice by link_to :remote
Asked Answered
G

11

34

I have a weird problem where JQuery is creating two AJAX requests for a link_to method. I am developing a Rails 3 app with JQuery for UJS. I have a toggle link which toggles between 'Follow' and 'Unfollow'

My link is rendered as below:

<span id="follow_link">
  <a href="/tfollow_artist?id=8103103" data-method="post" data-remote="true" id="follow_artist" rel="nofollow">Unfollow</a>
</span>

and my controller is setup so:

def tfollow_artist
  @artist = Artist.find(params[:id])
  if current_user.following?(@artist) 
    current_user.stop_following(@artist)
  else 
    current_user.follow(@artist)
  end
 end

which finally renders a js as:

 $('#follow_link').html('<%= escape_javascript(render :partial => "follow") %>');

Which essentially replaces html contents of the '<span id="follow_link">...</span> with the same URL only with the text being different. For example, above will now be rendered as:

<span id="follow_link">
  <a href="/tfollow_artist?id=8103103" data-method="post" data-remote="true" id="follow_artist" rel="nofollow">Follow</a>
</span>

However this is somehow causing JQuery to make two AJAX requests.

Can any one see what is wrong here?

I am using 'jquery-rails' gem which is copying the latest jquery-ujs file to my app. JQuery version is 1.4.3

Guttural answered 20/11, 2010 at 8:40 Comment(4)
even im facing this error.. any solutions ?Hypocaust
Same problem here. Still searching for a solution.Tropo
Ditto on the problem.. you ever figure this one out?Winnow
Also facing the same problem... jquery-rails version 1.0.16.Vulgus
V
27

Thanks to this dialog:

https://github.com/rails/jquery-ujs/issues/208

I was able to discover that jquery and jquery_ujs were getting included twice.

I guess the jquery-rails gem automatically puts them into application.js, and then I had them included in application.js as well.

Seems like for whatever reason application.js automatically bundles everything in app/assets/javascripts/ - even when I remove all the requires.

So, if your :remote => true forms are getting submitted twice, try checking application.js.

Hope this helps!

UPDATE: I believe this might have had something to do with me pre-rendering my assets without using a digest, so then when my development environment adds script tags in the html head dynamically from the requires in app/assets/application.js, it also adds one for what should be an empty dynamic application.js, except the static one from public/assets gets loaded. Confusing? Yep!

Vulgus answered 15/10, 2011 at 13:21 Comment(0)
P
17

I had the same issue, fixed by commenting this line

\#config.assets.debug = true

in development mode

Pannikin answered 19/11, 2011 at 19:51 Comment(2)
this worked for me and the duplicate ajax calls were eliminated, but I didn't need to do this on my other workstation for some reason. What does this setting do and why do we need to turn it on/off, when to use it?Surrender
This still works. Anyone know off the top his/her head why?Overcrop
F
5

I had simmilar issue. Running following rake tasks resolved my problem.

rake tmp:clear
rake assets:clean
Fluorite answered 17/5, 2013 at 12:45 Comment(0)
U
3

I think what is happening is that your JavaScript is not stopping the link from being executed by the browser. So you get the AJAX request then the browser request.

There is an explanation and solution for this in Rails Cast 174. Text explanation here, about 3/4 of the page down.

Undershirt answered 20/11, 2010 at 9:42 Comment(2)
Thanks for the link and explanation. This makes sense. However, the Javascript which makes the remote call when link_to :remote is called already uses "live" method and "prevents" defaults (this is in jquery-ujs' rails.js (github.com/rails/jquery-ujs/raw/master/src/rails.js): $('a[data-remote],input[data-remote]').live('click.rails', function (e) { $(this).callRemote(); e.preventDefault(); }); So not sure if there is something else which is going here.Guttural
doesn't it depend on the return value instead?Gewgaw
J
2

I was having the same issue: duplicate requests when using :remote => true. My issue was due to using Heroku and precompiling assets. I am precompiling assets prior to deploying to Heroku (rake assets:precompile). This essentially creates a duplicate copy of your asset pipeline in your public folder. So the same thing was happening as mentioned by Docunext: there were multiple javascript files handling each request.

It gets fixed if I remove the assets in the public directory when working locally (git rm -rf public/assets). After removing the assets from the public directory, it stopped sending multiple requests

Joycejoycelin answered 5/6, 2012 at 11:48 Comment(0)
D
1

Try this code.... to prevent double clicks on remote links..

$('a[data-remote=true]').live('ajax:before', function () {
   if ($(this).attr('ajax-loading')) {
     return false;
   } else {
     $(this).attr('ajax-loading', true);
   }
}).live('ajax:complete', function () {
  $(this).removeAttr('ajax-loading');
});

Gist

Drifter answered 25/4, 2012 at 6:45 Comment(0)
B
1

Also for me the same problem: twice XMLHttpRequest on a link_to ... :remote => "true"

I've solved, in

locals/application.rb :

by commenting

// config.assets.paths << Rails.root.join('vendor','assets','stylesheets','javascripts')

and uncomment

config.action_view.javascript_expansions[:defaults] = %w(jquery jquery-ui application)

then I forgot to do after my last git pull. I hope help someone.

Brasilin answered 13/10, 2015 at 16:3 Comment(0)
I
0

JavaScript files you want as :defaults (application.js is always included).

 config.action_view.javascript_expansions[:defaults] = %w(jquery rails)

Commented line is clearly saying that application.js is always included. In my application I have added application in defaults. So for ajax .submit it was creating two records in my application.

Inrush answered 29/11, 2011 at 5:27 Comment(0)
C
0

i faced the same problem just now. checked out all the code changes and tried other things but to no avail. finally cleared the browser cache. that helped.

Causation answered 10/10, 2012 at 14:6 Comment(0)
R
0

If you are not able to find out where the ujs file is loaded twice, simply copy this code into rails.js / application.js (preferably not here)

var alreadyInitialized = function() {
    var events = $(document).data('events');
    return events.click && $.grep(events.click, function(e) { return e.namespace === 'rails'; }).length;
    }

if ( alreadyInitialized() ) {
    $.error('jquery-ujs has already been loaded!');
}
Rowena answered 21/11, 2013 at 8:1 Comment(0)
C
0

Building on Eugene's answer, note that if you're developing after you've locally precompiled your assets for production, like...

bundle exec rake assets:precompile RAILS_ENV=production

...then as you continue development the Rails AssetPipeline will want to serve both your uncompiled and your compiled assets.

One way to fix it is with Eugene's Rails' standard rake task. Another way is by simply removing those pesky precompiled production-ready assets with something like

$ rm -rf #{Rails.root}/public/assets
Caracara answered 19/7, 2015 at 11:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.