Rails, jQuery and the nitpicky AJAX glue [Updated]


This blog post is older than 4 years and its content may be out of date.

UPDATE : A better solution has been found with the help of one of my friends. Find it at the bottom of this post.

UPDATE 2 : An even better solution has been proposed by that very same friend. See at the bottom of this post.

I’m currently working on some generic “manipulate your database data” interface programmed in Rails and wanted to make the UX friendlier by reloading the table after the user reordered some of the entries in the table using jQuery-UI-sortable. My approach to this was to create a js.erb template for the sorting action in that particular controller, rendering the table partial and making them available in the success handler of the AJAX call in sortable() (inspired and taken from Bens primer on sortable bootstrap tables):

   axis: 'y'
   items: '.item'
   # highlight the row on drop to indicate an update
   stop: (e, ui) ->
       ui.item.children('td').effect('highlight', {}, 1000)
   update: (e, ui) ->
       item_id = ui.item.data('itemId')
   position = ui.item.index()
   request = $.ajax
       type: 'PUT'
       url: $(this).data('updateUrl')
       dataType: 'json'
       data: { term: { id: item_id, row_order_position: position } }
       (data) -> eval(data.content)

request.success never evaluated and I pulled my remaining hair in frustration about this madness. Then I remembered a similar problem I had in the past. The Rails AJAX glue is somewhat nitpicky about when it considers an AJAX request to be successful. Turns out that my controller must render a JSON object containing message: "Success"; as a response to an AJAX request in order for it to be considered successful. After changing my controller code to this code, everything worked as expected:

def sort
   @t = Term.find(params[:term][:id])
   @t.update_attribute :row_order_position, params[:term][:row_order_position]
   @s = Seminar.find(params[:seminar_id])
   @t = @seminar.terms.rank(:row_order)
   @content = render_to_string "terms/sort"
   render json: {message: "Success", content: @content}

I hope this is helpful to other developers facing the same difficulties.

UPDATE : After a quick chat with one of my friends, I’ve come up with the following solution in my controller code:

def sort (...)
    @content = render_to_string "terms/sort"
    render json: {content: @content}, status: :ok

It seems that Rails does not default to a status of :ok, but needs you to make explicit when a request is to be considered successful.

UPDATE 2 : Okay. So Rails does default to a status of :ok and I need to get rid the eval inside of my success handler. No matter the language - eval gives me a chilly feeling down my spine. Here’s the code:

def sort (...)
    @content = render_to_string "terms/sort"
    render json: {content: @content}, status: :ok
request.success (data) -> $('.table').html(data.content)

I can even convert this ERb template to HAML now!