I recently implemented some cross-domain AJAX using jQuery. I wanted to POST data using JavaScript's XMLHttpRequest to another site, and this required the use of the new HTTP access control headers
You can try out the functionality on the new site litepanels.co.nz - simply click the "Contact Us" link in the footer and send us message. That form POSTs data to http://www.lucidsystems.co.nz/company/contact-us/send which is responsible for actually sending us a message.
To make this work, you need to respond to the HTTP OPTIONS method with appropriate access control headers. When the client web browser tries to send the XMLHttpRequest, it first initiates an OPTIONS request to the same URI, and checks the headers. These headers specify things such as what domains can make XMLHttpRequests to this URI.
Server-side implementation
Here is an example of how to respond to the HTTP options method using the Utopia framework:
ACCESS_CONTROLS = {
	"Access-Control-Allow-Origin" => "*",
	"Access-Control-Allow-Headers" => "X-Requested-With",
	"Access-Control-Max-Age" => "60"
}
on 'index' do |request, path|
	# ...
	if request.options?
		# Allow AJAX requests from different domains.
		return :status => 200, :headers => ACCESS_CONTROLS
	end
	
	# ...
endYou can check this using curl -i -X OPTIONS $URI:
$ curl -i -X OPTIONS http://www.lucidsystems.co.nz/company/contact-us/index 
HTTP/1.1 200 OK
Date: Fri, 06 May 2011 02:25:28 GMT
Server: Apache/2.2.16 (Debian)
X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.5
<span class="highlight">Access-Control-Allow-Headers: X-Requested-With</span>
<span class="highlight">Access-Control-Allow-Origin: *</span>
<span class="highlight">Access-Control-Max-Age: 60</span>
Content-Length: 0
Status: 200
Content-Type: text/plain
One problem I encountered when executing XMLHttpRequests was the fact that they process 3xx redirections transparently. So, if you return a 3xx redirect, it won't actually return this status code to your handler, but instead process the redirectionXMLHttpRequests return 2xx or 4xx status codes.
It is also important that controllers return the access control headers.
if request.xhr?
	# You also need to provide access control headers here.
	return :status => :success, :headers => ACCESS_CONTROLS
else
	return redirect(params["from"] ? "success" : "success-no-reply")
endClient-side implementation
On the litepanels.co.nz, I use JavaScript and jQuery to serialize the contact form and send this data to http://www.lucidsystems.co.nz/company/contact-us/send:
$(function() {
	// The contact form element
	var contact = $("#contact");
	contact.validate({
		rules: {
			subject: "required",
			from: {
				email: true
			},
			message: "required"
		},
		submitHandler: function() {
			$('#contact-popup .main').slideUp();
			$('#contact-popup .sending').slideDown();
			
			$.ajax({
				url: contact.attr('action'),
				type: 'post',
				data: contact.serialize(),
				crossDomain: true,
				headers: {
					"X-Requested-With": "XMLHttpRequest"
				},
				success: function() {
					$('#contact-popup .sending').slideUp();
					$('#contact-popup .success').slideDown();
				},
				error: function(request, status, error) {
					$('#contact-popup .sending').slideUp();
					$('#contact-popup .error').slideDown();
				}
			});
		}
	});
})
jQuery by default doesn't set X-Requested-With for cross-domain requests, so you need to do this manually.
Further Reading
HTTP Access Controls