Rails AJAX File Uploads

So everyone knows you can't use AJAX to upload a file. For security reasons, Javascript isn't allowed access to the client's filesystem. If someone wants a file upload without reloading the page, there are generally two options:

  • Use a little bit of flash, such as Uploadify or SWFUpload
  • Use an IFrame to post it and give the appearance of AJAX(though you are technically doing a regular HTTP request)

Now I'm using the JQuery Javascript library, along with the JQuery Form Plugin, which easily lets turn a regular form into an AJAX form. While I was googling around trying to figure out which method I wanted to use for my AJAX file uploading, I discovered that the JQuery Form Plugin already supports AJAX file uploading(via the IFrame Technique mentioned above). I've implemented the IFrame method before, but the plugin makes it much easier to do. I was able to include f.file_field :photo in my form, and everything just worked. Here is how it works(btw, the markup is in HAML, not ERB):

View

.ajaxform
  - form_for question do |f|
    = f.label :description
    = f.text_area :description

    = f.label :photo
    = f.file_field :photo

Javascript

$(document).ready(function() {
  var form = $('.ajaxform').find('form:first');
  var options = {//see http://jquery.malsup.com/form for form options};
  form.ajaxForm(options);
});

And you can handle things in your controller the same way you always do(depending on what plugin you are using to handle file uploads). See you next time!

-Ralph





Rails Database Session Store Error

One of the legacy Rails apps that I am upgrading stores a lot of session data in the database. I started getting this error message: "marshal data too short". This is because the Sessions table in MySQL stores the data in a column of type text. When the amount of data stored in this column is > 64k, the data ends up being truncated, which causes checksums to fail and this error message to pop up. The fix: change the column type to 'longtext'(mysql only?):


class ChangeSessionsToLongtext < ActiveRecord::Migration
  def self.up
    change_column :sessions, :data, :longtext
  end

  def self.down
    change_column :sessions, :data, :text
  end
end




Shuffle ActiveRecord Results Randomly

Just a quick post today - if you want to randomize or shuffle a set of Objects from an ActiveRecord find, the best way is to do it in the database. MySQL has the 'RAND()' function and SQLite3 uses 'RANDOM()'. You can just pass these in as text in the :order argument of your find:


#mysql
Foo.find(:all, :order => 'RAND()')
#sqlite3
Foo.find(:all, :order => 'RANDOM()')

And of course, you can pass the same thing in to will paginate to order them randomly.

-Ralph




Bort on Rails 2.3.2

I recently decided to try starting an app using Bort, a base Rails application that comes with many things conveniently setup:

  • RESTful Authentication with roles and OpenID
  • will_paginate
  • RSpec
  • Capistrano
  • Exception Notifier
  • Asset Packager - packages your CSS/JS

Sounds great! But the current version is setup for Rails 2.2.0, and the most recent release of Rails is 2.3.2 . Here is what I needed to do to get things working:

  ./script/plugin install git://github.com/rails/open_id_authentication.git --force
  ./script/plugin install git://github.com/sbecker/asset_packager.git --force
  mv app/controllers/application.rb app/controllers/application_controller.rb

And then change the RAILS_GEM_VERSION in config/environment.rb to '2.3.2' . I created a fork on github with these changes, and you can find it here. You can download it with this command:

wget http://github.com/balgarath/bort/zipball/master




Welcome to the blog!

I am still finishing up getting things together on here, and getting my old blog posts migrated to the new engine. Until then, you can check out my blog posts at: http://railsonedge.blogspot.com.




New Site

Well Here we are, now running on the newest version of Mephisto, Slicehost, Passenger, and Ruby Enterprise Edition.