Q:

rails 4 ajax event not triggering success

I'm working on my rails 4 demo app, and I've got a button that is meant to do some work on the server side, then return json with a success or failure message.
Similar to this question, I am seeing the response come back with a 200 code and the expected json payload, but the jQuery success event is not triggered-- to make it more confusing, it seems to be somewhat intermittent-- sometimes I get the proper action (showing a flash message and removing a div) but most of the time nothing happens.
Here's the button in the view:
<%= link_to 'Do Work', widget_path(:id => widget.id), id: widget.id, remote: true, method: :get %>

Here's the controller:
respond_to do |format|
  if widget.save
    // this json is returned properly
    format.json { render json: { status: 'success', msg: 'Widget created.', :content_type => 'text/json', type: 'info', item: 'widget' } }
  else
    format.json { render json: @user.errors, :content_type => 'text/json', status: :unprocessable_entity }
  end
end

The javascript in application.js:
var fade_flash = function() {
    $("#flash_success").delay(2000).fadeOut("slow");
    $("#flash_info").delay(2000).fadeOut("slow");
    $("#flash_warning").delay(2000).fadeOut("slow");
    $("#flash_danger").delay(2000).fadeOut("slow");
};
fade_flash();

var show_ajax_message = function(msg, type) {
    $("#notice").html('<div id="flash_'+type+'" class="alert alert-dismissable alert-'+type+'"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>'+msg+'</div>');
    fade_flash();
};

Here's the coffeescript in widget.js.coffee:
$ ->
  $("a[data-remote]").on "ajax:success", (e, data, status, xhr) ->
    alert('got here')
    console.dir(data)
    if data.status == 'success' 
        show_ajax_message(data.msg, data.type) 
        if data.item == 'widget'
            $('#widget_'+this.id).hide('slow')

A:

Turbolinks
Your problem is likely to be an issue with Turbolinks:

Turbolinks makes following links in your web application faster.
  Instead of letting the browser recompile the JavaScript and CSS
  between each page change, it keeps the current page instance alive and
  replaces only the body and the title in the head. Think CGI vs
  persistent process

Turbolinks basically loads your pages with Ajax (leaving <head> tags in place), loading your pages faster... but also causing your JS to not fire
Issue being JS works by binding to DOM elements at load. If DOM elements are not present, they can't be bound, causing problem

Fix
The way you need to fix this is to use javascript delegation
This works by binding events to a "container" element (typically document) and delegating down to the sub elements. This works because document is always present, and consequently JS will always be able to fire whether the DOM elements are present at load or not:
#app/assets/javascripts/application.js
var fade_flash = function() {
    $("#flash_success").delay(2000).fadeOut("slow");
    $("#flash_info").delay(2000).fadeOut("slow");
    $("#flash_warning").delay(2000).fadeOut("slow");
    $("#flash_danger").delay(2000).fadeOut("slow");
};

var show_ajax_message = function(msg, type) {
    $("#notice").html('<div id="flash_'+type+'" class="alert alert-dismissable alert-'+type+'"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>'+msg+'</div>');
    fade_flash();
};

$(document).on("read page:load", fade_flash);

#app/assets/javascripts/widgets.js.coffee
$ ->
  $(document).on "ajax:success", "a[data-remote]", (e, data, status, xhr) ->
    // meaningless comment to get past edit limit-- added comma in line above
    alert('got here')
    console.dir(data)
    if data.status == 'success' 
        show_ajax_message(data.msg, data.type) 
        if data.item == 'widget'
            $('#widget_'+this.id).hide('slow')

