views:

239

answers:

2

I'm using Rails with jQuery, and I'm working on a page for a simple site that prints each record to a table. The only editable field for each record is a checkbox. My goal is that every time a checkbox is changed, an ajax request updates that boolean attribute for the record (i.e., no submit button).

My view code:

<td>
<% form_remote_tag :url => admin_update_path, :html => { :id => "form#{lead.id}" } do %>
   <%= hidden_field :lead, :id, :value => lead.id %>
   <%= check_box :lead, :contacted, :id => "checkbox"+lead.id.to_s, :checked => lead.contacted, :onchange => "$('#form#{lead.id}').submit();" %>
<% end %>
</td>

In my routes.rb, admin_update_path is defined by

  map.admin_update 'update', :controller => "admin", :action => "update", :method => :post

I also have an RJS template to render back an update. The contents of this file is currently just for testing (I just wanted to see if it worked, this will not be the ultimate functionality on a successful save)...

page << "$('#checkbox#{@lead.id}').hide();"

When clicked, the ajax request is successfully sent, with the correct params, and the action on the controller can retrieve the record and update it just fine. The problem is that it doesn't send back the JS; it changes the page in the browser and renders the generated Javascript as plain text rather than executing it in-place.

Rails does some behind-the-scenes stuff to figure out if the incoming request is an ajax call, and I can't figure out why it's interpreting the incoming request as a regular web request as opposed to an ajax request.

I may be missing something extremely simple here, but I've kind-of burned myself out looking so I thought I'd ask for another pair of eyes. Thanks in advance for any info!

A: 

In your controller you need to specify the proper response. Since you didn't post the controller I'll just try to fill in the blanks.

def update
  # Update something
  respond_to do |format|
    format.js # this renders your rjs file
  end
end

Specifying the format tells the rails app to interpret the javascript instead of just sending it back as text.

The other option instead of using rjs is to do an inline rjs block like this:

render :update do |page|
  page.replace_html  'user_list', :partial => 'user', :collection => @users
  page.visual_effect :highlight, 'user_list'
end

Only use the inline rjs if you will be doing minimal changes to the interface that can be put into one or two lines. Anything more should be in it's own rjs file.

Nick Hammond
I updated the controller to use an explicit respond_to block and I get the same response: the generated JS is displayed as plain text in the browser. I think the problem is that when I use jQuery to .submit() the form, it's not running the onsubmit="..." code that was defined by the form_remote_tag helper. It's just submitting the form regularly. This prompts me to ask: why wouldn't the onsubmit value in the form element be executed when calling $(form).submit() using jQuery?
whazzmaster
A: 

This question is related to this one, but the answer varies slightly. I had to create a new way to submit the form, since the default jQuery submit() method does not submit as a 'script' and certainly does not fire the code that Rails generates in the onsubmit="..." handler via the form_remote_tag helper.

The solution was to create a new function as the linked answer suggests, but the contents are slightly different:

jQuery.fn.submitWithAjax = function() {
    jQuery.ajax({data:jQuery.param(jQuery(this).serializeArray()) + '&amp;authenticity_token=' + encodeURIComponent('<%= form_authenticity_token %>'), dataType:'script', type:'post', url:'/update'}); 
    return false;
};

This is brittle right now-- notice that I insert rails' form_authenticity_token into the Javascript, but really the method (post) and the url (/update) should also be generated rather than hardcoded.

Things are working A-OK now.

whazzmaster