Rails 4 how to catch ajax:success event
The button_to
helper builds a form around a submit button. And the form is what receives the data-remote
attribute (see: http://apidock.com/rails/ActionView/Helpers/UrlHelper/button_to). So, I'd try this:
$('.rate-btn').closest('form').on('ajax:success', function() {
console.log('ajax:success!')
});
Since you're on Rails 4.0 I'm guessing you're on jQuery 1.9. Binding for events seems to have changed a bit there. So that could be part of it if this has worked for you before. Using .on()
for event binding has been preferred over .bind()
since 1.7.
emersonthis
I am a designer, developer, and problem solver. I make websites and stuff. I work with brazen startups, modest individuals, earnest small business, and everyone in between. I care as much about how things look as how they work. I enjoy writing and teaching what I know. The best part about my job is constantly learning new things.
Updated on August 01, 2022Comments
-
emersonthis over 1 year
I'm on Rails 4.0.
I'm sending an event like this (note the :remote=>true):
<%= button_to 'yes', {controller:'videos', action:'rate', id: video.hashed_id, yesno:'yes'}, {:remote=>true, :class=>"rate-btn yes-btn btn btn-default btn-sm"} %>
My controller looks like this:
def rate video = Video.find_by( hashed_id: params[:id]) action = params[:yesno] puts video.hashed_id puts action respond_to do |format| if (action=='yes') new_rating = video.rating==1 ? 0 : 1 video.update( is_new:0, rating: new_rating ) format.html { redirect_to controller:'projects', action: show, id: video.project.hashed_id } format.json { head :no_content } format.js { render :nothing=>true } end if (action=='no') new_rating = video.rating==-1 ? 0 : -1 video.update( is_new:0, rating: new_rating ) format.html { redirect_to controller:'projects', action: show, id: video.project.hashed_id } format.json { head :no_content } format.js { render :nothing=>true } end end end
I'm kind of winging it with the format.json/format.html because I don't fully understand which one should apply from an AJAX request.
On the view (where the button lives) I have this:
$(document).ready( function($) { console.log('ready'); $(document).ajaxSuccess( function(data) {alert(data);} ) $(document).ajaxError( function(data) {alert(data);} ) $('.rate-btn').closest('form').on('ajax:success', function() { console.log('ajax:success!'); }); $('.button_to').bind("ajax:success", function() { console.log( 'test' ); }); });
After clicking the button, I get
ready
in the console, but no matter what I do I can't get thetest
to show up in the console. What am I missing?Update:
I tried clicking the button while watching /log/development.log and this is what I see:
Started POST "/videos/rate/lq7lv3218c/yes" for 127.0.0.1 at 2013-08-29 17:14:59 -0400 Processing by VideosController#rate as JS Parameters: {"authenticity_token"=>"es4wPqFrxxxxxFsbHQR/gAzofDC+ZwYsiiJ7RAQZUHk=", "id"=>"lq7lv3218c", "yesno"=>"yes"} [1m[36mVideo Load (0.3ms)[0m [1mSELECT `videos`.* FROM `videos` WHERE `videos`.`hashed_id` = 'lq7lv3218c' LIMIT 1[0m [1m[35m (0.1ms)[0m BEGIN [1m[36mSQL (0.3ms)[0m [1mUPDATE `videos` SET `rating` = 0, `updated_at` = '2013-08-29 21:14:59' WHERE `videos`.`id` = 18[0m [1m[35m (0.3ms)[0m COMMIT Rendered videos/rate.html.erb (0.0ms) Completed 200 OK in 7ms (Views: 2.0ms | ActiveRecord: 1.1ms)
I'm a rails n00b but it looks ok to me.
-
emersonthis over 10 yearsThanks. I was trying with
.on
originally but when it didn't work. I updated the question with all of the event listeners I'm using for debugging. -
pdobb over 10 yearsIt would help to see what's returned by the AJAX request too. I usually use the firebug console for this. Are you able to get that? It's highly suspect that the log shows the action rendering an
.html.erb
file for the action (Rendered videos/rate.html.erb
) when the request clearly came in as a JS request. -
emersonthis over 10 yearsI'll fiddle with Firebug. Would the .html.erb issue be caused by the fact that I created a /view/videos/rate.html.erb file? I did it just in case it was necessary (CakePHP requires it) but didn't think it could hurt anything.
-
pdobb over 10 yearsThe existence of the
rate.html.erb
file won't influence the controller action. So, for example, if you deleted it I'd expect it to balk about the missing template file then. What happens if you take out the format responders other than theformat.js
one? -
pdobb over 10 yearsAha! Look at RDX's answer here: stackoverflow.com/questions/16637522/… -- basically you don't automatically get to fall int the
format.js
bucket just because you didremote: true
on a form. You've got to specify the format in the url of the form. -
emersonthis over 10 yearsProgress! I added a tag to load jQuery in the layout and it must have been banging into whatever Rails does by default because when I removed my javascript tag, now clicking the ajax button triggers the "ajax:error" event:
$('.rate-btn').closest('form').on('ajax:error', function() { console.log('ajax:error!'); });
So I think the question now is why it's an error. I addedlogger.debug request.format
to the controller and it return 'text/javascript'. Is that what it should be? -
emersonthis over 10 yearsWoah MORE news... it turns out my view file couldn't be empty... or something. I seem to have solved the problem but I'm still scratching my head as to what is/was going on. I posted an answer describing what I did and I'd LOVE to hear your thoughts.
-
pdobb over 10 yearsIt sounds like you've got a gem that's loading jQuery then. (Do you have the
jquery-rails
gem, for example?) Unfortunately, that's how it seems to be going lately with Rails but I'm not sure that's ideal. But that's another topic. I'm not sure why having content in the view file would change the response or in what way that would affect the events... But I still think you should figure out how to ensure you're getting the right format responder based on your request. -
pdobb over 10 yearsTo force the format you would add a
format: json
parameter to the form's post url. Or maybeformat: js
. So in your case:{controller:'videos', action:'rate', id: video.hashed_id, yesno:'yes', format: 'json'}
. By the way, you should really try to use named routes: guides.rubyonrails.org/… -
pdobb over 10 yearsI would recommend removing the templates (view files) and format responders that you don't intend to use / have an explicit need for.
-
emersonthis over 10 yearsUrgh. I'm still grinding away at this and I'm close, but I still can't get the data to pass from the controller back to the view. In the controller I have
format.json {render json: 'test' }
and in the view I have$('.rate-btn').closest('form').on('ajax:success', function(e, data, status, xhr) { console.log(data); });
. When I click the button I getnull
. I don't get it. -
pdobb over 10 yearsIt may need to be a valid json object you render. A quick test is to do
format.json { render json: video }
, which will render yourvideo
object as json (video.to_json
is implied by the render formatter type). Also, make sure you have the right attribute by usingconsole.log(e, data, status, xhr)
. Not sure if theajax:success
event will pass the data back in the 1st or 2nd attribute. -
emersonthis over 10 yearsI tried with
format.json {render json: video }
and I still getnull
for data. I'm logging all four parameters passed by ajax:success so I'm pretty confident I'm checking the right one. -
emersonthis over 10 yearsAha. I removed
/views/videos/rate.json.erb
and I immediately started throwing errors. So despite myformat.json {render json: video }
Rails is still relying on the view file. Not sure why that is. But when I place a valid json string in that view file I do see it in the data parameter. Not sure where to go with this info. -
pdobb over 10 yearsThat must mean that the format wasn't actually
json
. You can put a debugger inside of the block for those formatters and see where it's landing.format.json { debugger; render json: video }
. If it doesn't hit then it didn't fit. Sounds like it's not hitting any of them maybe? I think you should read through this article. Looks to be great! alfajango.com/blog/rails-3-remote-links-and-forms -
pdobb over 10 yearsAnd don't forget to read part 2 as well: alfajango.com/blog/… -- very informative!
-
pdobb over 10 yearsThe key here is probably to use the
xhr.responseText
instead of thedata
attribute to get the response data. -
emersonthis over 10 yearsFigured it out!! There was a bug higher up in my code that was causing the function to return
nil
BEFORE therender json: @object
got a chance to work. So that's why the template was rendering and also why the variables weren't getting passed. -
pdobb over 10 yearsPhew! Thanks for the closure :).
-
Arup Rakshit over 8 yearsNice explanation indeed.