Rails Security

I read a post in another blog today about SQL Injection in Rails. The poster raised the specter of insecure code making the database vulnerable through the use of SQL Injection.

For those that don’t know, SQL Injection is where an attacker ‘injects’ code into a web response that makes the site return data that it was not designed to. SQL servers will try to parse any query that they receive, so it is up to the programmer to ensure that anything a hacker might throw at a database gets rejected before the query reaches the SQL Server. Sometimes, despite the best intentions of the coder, a vulnerability gets exposed in the Rails framework at which point it might might be necessary to do some urgent work to address the issue.

The post mentioned above did nothing to explain how to address the issue of SQL Injection in Rails; instead it was a hook to get the reader to attend a particular talk at an upcoming Rails conference. That’s not a lot of help if you can’t attend the event.

Giving thought to Security Vulnerabilities is something that doesn’t often come naturally to coders; especially self taught ones. A bit like Testing, it’s not at the glamorous end of development and too often gets overlooked. Now security issues have been around for as long as people have written code and others have tried to hack it, so addressing potential security vulnerabilities by using good coding practice must be part of the development process.

Many good people have already written much good stuff on this topic, so I’m not going to add to it. Instead, I’ll point you in the direction of a few sites that I consider will be of the best help to you and exhort you to take the issue of the security of your web site very seriously. There’s absolutely no point in producing a wonderful looking site that uses all sorts of gee-whiz effects if your client is going to find that their site or their database is going to be hacked.
The following links take you to existing sites that deal with Rails Security in an excellent manner:

  • http://guides.rubyonrails.org/security.html – This is the Security page on the Rails site and these people know what they are talking. Read and re-read until you understand what the issues are and how to deal with them.
  • http://railscasts.com/ – Ryan Bates’ Railscasts site contains a whole host of material pertaining to development in the Rails environment and some of it is devoted to security issues. The Pro subscription costs $9 a month but as a Rails developer you’ll never spend a better $9.
  • http://rails-sqli.org/ – This site is devoted to what not to do when coding in Rails. It’s very well worth taking a look at this.
  • https://groups.google.com/forum/#!forum/rubyonrails-security – This is the source that you need to subscribe to if you can’t find the help you need. Very friendly advice given from participants.
  • http://brakemanscanner.org/ – This is a gem in the real sense of the word. An Open Source Rails Security Scanner that you can include in your gem list. See http://railscasts.com/episodes/358-brakeman for an excellent Railscast on how to use.
  • https://isc.sans.edu – A bit over the top for this post perhaps; you’ll need to sign up for this (although it costs nothing) before you’ll be able to search for Rails specific issues.

I hope at least one of the above links helps!

Rails Date Formats

First published on Fencore Ltd.’s Posterous page on December 3rd, 2010

(Note that the comment about working in Britain is no longer true, as I now reside in the USA.)

I don’t know about you but I get confused when working with dates as the built-in formats don’t work for me.
Ruby has a Date library that implements both the Date and DateTime classes and Rails extends these in its ActiveSupport library. There is also a Time class and, of course, these things cannot exist in isolation from each other.
As I work in Britain, I need to be able to produce dates in British format. I add custom formats to the Rails DATE_FORMATS hash by creating a file in config/initializers with the following contents:

Date::DATE_FORMATS[:british] = "%d/%m/%Y"
Date::DATE_FORMATS[:british_long] = "%d %B, %Y"
Date::DATE_FORMATS[:british_long_ordinal] = lambda { |date|
date.strftime("#{ActiveSupport::Inflector.ordinalize(date.day)} %B, %Y") } # => "25th April, 2007"

According to the documentation (for Rails 3.0.3 look at the ActiveSupport RDocs and then for to_formatted_s(format = :default) in DateTime), the file should be called config/initializers/time_formats.rb but it turns out that is is more of a suggestion than a ‘must do’. I found this out when I called I called it date_formats.rb by mistake; in fact I tried calling it splat.rb and it still worked, so perhaps something a little more generic like date_time_formats.rb would be better.
With that in place, and noting that to_formatted_s is aliased to to_s, you can do things like:

> date = Date.today => Fri, 03 Dec 2010
> date.to_s # this is the default output
=> "2010-12-03"
> date.to_s(:long) # this is pre-defined
=> "December 3, 2010"
> date.to_s(:british)
=> "03/12/2010"
> date.to_s(:british_long)
=> "03 December, 2010"
> date.to_s(:british_long_ordinal)
=> "3rd December, 2010"

You can do a similar thing with times (although I find no need to) and of course, you can define your own formats to satisfy your own local needs.
What about converting from a string to a Date or DateTime object?
Well, the strptime method is part of the Ruby language, so the following works:

> Date.strptime("31/01/2010", "%d/%m/%Y")
=> Sun, 31 Jan 2010 DateTime.strptime("31/01/2010", "%d/%m/%Y")
=> Sun, 31 Jan 2010 00:00:00 +0000

Note that I am using Ruby 1.9.2, although I believe nothing has changed from 1.8.x

Ruby Snippet – next day of week given date

First published on Fencore Ltd.’s Posterous page on October 13th, 2010

I needed the ability to work out the date of the next weekday after a given date, e.g. what is the date of the Saturday after the 1st December? The following will do it:

#date_convert.rb
require 'date'
require 'active_support/core_ext'
Date::DATE_FORMATS.merge!({british: "%d/%m/%Y"})
class DateConvert
  # usage:
  # date_of_next( day_name, date) where day_name is a string or symbol representation of a full weekday name, e.g. :saturday
  # and date is either a valid Date object or a string representation of a date
  def date_of_next( day_name, date = Date.today.to_s(:british))
    # Note that config/initializers/date_formats.rb has been created with the following lines:
    # Date::DATE_FORMATS[:british] = "%d/%m/%Y" # => 25/4/2007
    # Date::DATE_FORMATS[:british_long] = "%d %B, %Y" # 25 April 2007
    # Date::DATE_FORMATS[:british_long_ordinal] = lambda { |date| date.strftime("#{ActiveSupport::Inflector.ordinalize(date.day)} %B, #
    # day_name must be a string value representing the full day name (or a token equivalent)
    # date must be a valid Date
    #
    # date_of_next( "saturday") is valid
    # date_of_next( "Saturday") is valid
    # date_of_next( :Saturday) is valid
    # date_of_next( "sat", Date.today) is invalid - invalid day_name
    # date_of_next( :saturday, "2010/11/31")) is invalid - ArgumentError: invalid date
    #
    date = date.to_s(:british) if date.kind_of?(Date)
    which_day = (day_name.downcase.to_s + "?").to_sym
    (1..7).each do |inc|
      begin
        date_object = Date.strptime(date, "%d/%m/%Y")
        return date_object + inc if (date_object + inc).send(which_day)
      rescue
        puts "Enter the day as a string or symbol representation of a full weekday name, e.g. :saturday"
        puts "Enter the date as a string value of the form dd/mm/yyyy"
        return
      end
    end
  end
end

require '/Users/martin/work/utils/date_convert.rb'
describe DateConvert, "#date_of_next" do
  before(:each) do
    @dc = DateConvert.new
  end
  it "returns a date object when given a valid day of the week as a string" do
    @dc.date_of_next("saturday").should be_an_instance_of(Date)
    @dc.date_of_next("Saturday").should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week as a symbol" do
    @dc.date_of_next(:saturday).should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week and a valid date as a string" do
    @dc.date_of_next("saturday", "9/11/2010").should be_an_instance_of(Date)
  end
  it "returns a date object when given a valid day of the week and a valid date as a Date object" do
    @dc.date_of_next("saturday", Date.today).should be_an_instance_of(Date)
  end
  it "raises an exception when given a valid day of the week and a invalid date as a string" do
    @dc.date_of_next("saturday", "2010/11/9").should raise_exception()
  end
  it "raises an exception when given a day of the week in invalid format" do
    @dc.date_of_next("sat", "9/11/2010").should raise_exception()
  end
  it "returns a date for next saturday that should be a Saturday" do
    @dc.date_of_next("saturday").should be_a_saturday
  end
  it "returns a date for next sunday that should be a Sunday" do
    @dc.date_of_next("sunday").should be_a_sunday
  end
  it "returns a date for next saturday after '9/11/2010' that should be '13/11/2010'" do
    @dc.date_of_next("saturday", '9/11/2010').to_s(:british).should == '13/11/2010'
  end
end

Hope it helps.

Installing ri documentation for rails-3.0.0… File not found: lib and rvm

First published on Fencore Ltd.’s Posterous page on October 13th, 2010

I’ll put the bottom line first: if you’ve tried installing Rails 3 and received an ‘Installing ri documentation for rails-3.0.0… File not found: lib’ error and ended up with no Rdocs, you need to install the rdoc gem first. If you do that, the problem goes way and the install will work perfectly.
I’d been working on a Rails application for some time and had been using it as a learning experience – trying all sorts of new ideas but the wheels fell off last week.
Rails 2.3.8 had been producing lots of deprecation warnings and seeing that 2.3.9 addressed some of those, I thought I’d upgrade. Easy enough – download the new gems (and incidentally clog up my gem repository even more) make a couple of trivial changes to the environment.rb file and try it out. No issues so far.
I needed to move the application to a Windows box and tried freezing the gems into the vendor directory and then copying it across, having installed MySQL and used the Windows Ruby Installer. No luck this time; it’s been a long while since I’ve run Rails on a Windows box but it seems an even less friendly environment than it used to. Apparently the Ruby installer is compiled using a different compiler nowadays and some gems haven’t changed along with it. I needed to install different versions of some gems.
Recognising the existence of rvm, which allows different versions of Ruby to run on the same computer (although you need to use ‘pik’ on a Windows computer), and also of the Bundler gem, which is integral to Rails 3 and allows for better management of gems, I decided to try these out.
Too many changes at once? Darn right. Hindsight is a wonderful thing…
If you follow the instructions carefully, rvm installs easily enough. You can install different versions of Ruby and install different gems for each Ruby version. (rvm calls these gemsets).
In fact, rvm goes further than this – it enables the creation of many gemsets under each Ruby version, allowing you to create gemsets for specific applications. When using a specific gemset, you also have access to a global gemset under that Ruby version. Neat!
Using a file called .rvmrc, you can set things up so that a default Ruby and gemset are chosen when you ‘cd’ to a particular directory.
rvm is an excellent utility and full marks must go to Wayne Seguin and his helpers for developing it. My only carp is about the web documentation, which I really do not like but this is open source right? Live with it or offer to help out!
I did have one huge issue, however. After I had got everything installed to my satisfaction (or so I thought), I tried installing Rails 3.
Now, according to the Rails 3 web site, http://rubyonrails.org/download, you need Ruby, Rubygems and then you can install Rails. If you do and you do not have the rdoc gem installed (which will happen if you use rvm), you will get the error described. Rails will install and work, but you won’t have the documentation locally available. So make sure you have the rdoc gem installed first. (rdoc is also part of Ruby’s standard lib and Rubygems is supposed to install it too – so I guess someone’s not testing enough!)
I have set things up so that the following are available in the global gemset under Ruby-1.8.7; bundler, rake, rdoc, rdoc-data, and syntax. Rake is provided by the rvm setup; the rvm documentation had also stated that rdocs would be installed by default but this wasn’t the case and the rvm web site has had been amended to reflect that.
In my opinion, the Rails site should state that the rdoc gem needs to be installed before Rails (or better yet, make it transparent by including it in the Rails install itself). I’ve tried raisng the issue but so far the response has been that rdoc is not a Rails dependency…

Adding a line break to a Rails confirm message

First published on Fencore Ltd.’s Posterous page on July 13th, 2010

In Rails 2.3.8, the following is produced by the scaffold generator:

<td><%= link_to 'Destroy', common_contents, :confirm => 'Are you sure?', :method => :delete %></td>

If you want to break the ‘confirm’ message over multiple lines, it is important to note that the generator has enclosed the message in single quotes. To make the line break, use \n and change the single quotes to double quotes.

<td><%= link_to 'Destroy', common_contents, :confirm => "Danger/nAre you sure?", :method => :delete %></td>

You’ll then get

2010.7.13.fig1

Instead of

2010.7.13.fig2

Uploadify with Paperclip on Rails Tutorial

First published on Fencore Ltd.’s Posterous page on June 11, 2010

(Note that this is an old post and that things have moved on; Ruby2, Rails4, Uploadify in HTML5 format. An update will be provided eventually, but the following is the old post that I know some people at least found helpful.)

This tutorial was born out of a need to enable multiple uploads of photos for a site I am working on. The site requires that an admin uploads photos that users can then browse through.
In my searching through the web, I became aware of a certain amount of confusion. Using pure javascript seemed impossible but there is a Flash based multiple upload plugin for jQuery called ‘uploadify’ at http://www.uploadify.com.
(Re the pure javascript issue – I’d love this to be confirmed or otherwise, with a reference).
User authentication issues have been completely ignored – that would be the subject of a different tutorial and this one is going to concentrate on getting uploadify to work together with Paperclip, albeit in a basic form, with Rails.
Paperclip is a Rails gem that makes the uploading of files simple. See http://github.com/thoughtbot/paperclip for details. Using Paperclip means that the database will store details of the files in the database and the actual files in a folder. I will be using default values for Paperclip, which means that the files will be stored in public/system.
For reference, I am using Ruby 1.8.7, Rails 2.3.8 and SQLite Database Browser 1.3 to inspect and clean up the database. Start in the usual way:

rails uploader
cd uploader

Ensure that the nifty-generators gem is installed

sudo gem install nifty-generators

(where I use sudo, Windows users should run with administrator privilege) and then do the following:

script/generate nifty_layout
script/generate nifty_scaffold user name:string
script/generate nifty_scaffold upload user_id:integer
sudo gem install paperclip
sudo gem install mime-types
script/generate paperclip upload photo

(I actually used an app template for the above which is included in the code sample. If you haven’t used one, take a look at Ryan Bates Railscast #148 http://railscasts.com/episodes/148-app-templates-in-rails-2-3
I then used uploader_templat.rb, to create the first parts of the uploader project:

rails -m uploader_template.rb uploader

).
edit the config/database.yml file appropriately and run

rake db:migrate

add the following to config/environment.rb:

config.gem 'mime-types', :lib => 'mime/types'
config.gem 'paperclip'

add the following to the user model:

has_many :uploads

add and amend the upload model to the following:

attr_accessible :user_id, :photo
belongs_to :user
has_attached_file :photo

edit the show action in apps/controllers/users_controller.rb

def show
  @user = User.find(params[:id], :include => :uploads)
end

edit the apps/views/users/show.html.erb file to the following:

<% title h(@user.name) %>

<h3 id="photos_count"><%= pluralize(@user.uploads.size, "Photo")%></h3>

<div id="uploads">
  <%= render :partial => @user.uploads %>
</div>

<h3>Upload a Photo</h3>
<% form_for Upload.new(:user_id => @user.id), :html => {:multipart => true} do |f| %>
  <%= f.hidden_field :user_id, "value" => @user.id %>
  <p>
    <%= f.file_field :photo %>
  </p>
  <p><%= f.submit "Upload" %></p>
<% end %>

<p><%= link_to "All users", users_path %></p>

Don’t omit the :html => {:multipart => true} or nothing will happen!
In uploads_controller, edit the redirect_to @upload in the create action as follows:

redirect_to @upload.user

Delete the scaffolded views from the apps/views/uploads directory and create a file called apps/views/uploads/_upload.html.erb and then insert the following code:

<div class="upload">
  <%= image_tag upload.photo.url %>
</div>

Add the following to the config/routes.rb and delete the index.html.erb from the public directory

map.root :controller => 'users'

You should now be able to run localhost:3000/users. Create some users, e.g.

fig1

Then navigate and create images one by one in the traditional html manner.
You’ll need some images to upload; I’ve created some small ones and stored them in a folder called pics off the rails application directory. You can pick them up from the sample code.
fig2
The show page will look like the following once the ‘Upload’ button is pressed:
fig3
Now we need to start adding in the uploadify functionality. Uploadify works with jQuery 1.2.x or greater. I’ve downloaded jQuery v1.4.2 and copied it the public/javascripts directory.
Uploadify can be found at http://www.uploadify.com. You need to expand the zip download and copy the files
jquery.uploadify.v2.1.0.js
swfobject.js and
uploadify.swf

Create public/javascripts/uploadify and store them in there.
The uploadify package also includes an uploadify.css file which should be stored in public/stylesheets and cancel.png which should be stored in public/images.
Replace the following line in app/views/layouts/application.html.erb

<%= stylesheet_link_tag 'application' %>

with the following two lines:

<%= stylesheet( 'application', 'uploadify') %>
<%= javascript( 'jquery-1.4.2') %>

These lines make use of some helper methods that were included when the the nifty_layout generator ran.
(app/helpers/layout_helper.rb). See http://github.com/ryanb/nifty-generators if you’ve not used these before.
The idea was to add javascript functionality ‘unobtrusively’ – making zero changes to the html/erb.
Unfortunately, I’ve not found that to be possible, so I’ve opted for running a partial from the app/views/user/show view that contains all the javascript. That way, if javascript is disabled, response degrades nicely to html only as the javascript partial will be ignored.
Add
<%= render :partial => “show” %> to the beginning of the app/views/user/show.html.erb file and create the partial _show.html.erb in the same app/views/user folder.
Add the following line to the show partial:

<%=javascript_include_tag "uploadify/swfobject", "uploadify/jquery.uploadify.v2.1.0.js" %>

Note that the detail here depends upon the version of uploadify that you have downloaded.
It’s sensible to test this now – run the app and choose ‘show’ for a user from the opening page. Check the log – if there are any routing errors for the two files, check the folder and file names now.
Assuming all is ok, add the following lines to the show partial:

<script type="text/javascript" charset="utf-8">
  $(document).ready(function() {
    $('#upload_photo').click(function(event){
      event.preventDefault();
    });
  $('#upload_photo').uploadify({
    'uploader' : '/javascripts/uploadify/uploadify.swf',
    'script' : '/uploads/create',
    'multi' : true,
    'cancelImg' : '/images/cancel.png'
    });
  $('#upload_submit').click(function(event){
    event.preventDefault();
    $('#upload_photo').uploadifyUpload();
    });
  });
</script>

The $(document).ready(function()) is a very common jQuery function (if you have not met jQuery, take a look at Ryan Bates Railscast #136 (http://railscasts.com/episodes/136-jquery ) as an intro).
The

$('#upload_photo').click(function(event){
  event.preventDefault();

stops the default html browse button functionality and the next part ($('#upload_photo').uploadify), fairly
obviously, loads the uploadify functionality, hence the change of appearance .
The

$('#upload_submit').click(function(event){
  event.preventDefault();
  $('#upload_photo').uploadifyUpload();
  });

stops the default html submit functionality and instead, fires the uploadify function.
Taking a look at the uploadify properties individually:
'uploader' : '/javascripts/uploadify/uploadify.swf' – path to the Flash file.
'script' : '/uploads/create' – this is the Rails script that will handle the uploading of the files.
Note this is not users/show, as the form_for in that script is for Upload.new.
'multi' : true – enables the uploading of multiple files
'cancelImg' : '/images/cancel.png' – this is the image that appears in the top right corner of each file
listing once ‘select’ has been clicked, allowing the user to cancel a file selection if the wrong one has been
clicked.
So, assuming that javascript is enabled, you should see the following:
fig4
Click the ‘BROWSE’ button and you should be able to select more than file, e.g.:
fig5

Clicking ‘Select’ will produce the following:
fig6
The red crosses are the ‘cancel.png’.
Click the ‘Upload’ button and you should see:
fig7
Oops .. well you didn’t expect it to be that easy, did you?
A look at the log suggests some problems to be solved:

Processing UploadsController#create (for 127.0.0.1 at 2010-06-10 10:43:32) [POST]
  Parameters: {"Filename"=>"1.jpg", "folder"=>"/users/", "Upload"=>"Submit Query",
    "Filedata"=>#}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

The parameters hash being delivered is very different from the usual one that Rails expects, so we’re going
to have to do some work with that. The InvalidAuthenticityToken problem often happens with Ajax calls as
the hidden field that embeds the AuthenticityToken is not present. Ajax calls have no understanding of
the Rails session.
One other thing we’ve omitted here is to use a respond_to block in the uploads controller, as we’re
submitting via javascript, right?
One thing at a time – let’s deal with the Authenticity issues first.
We need to return the form_authenticity_token, or the baked in Rails ‘protect_from_forgery’ stuff is rendered useless. Also, Flash knows nothing about Rails sessions, so we need to address this too; this is where Rack helps out.
Rack intercepts calls before they reach the server and can do good things with them for you. (See Ryan Bates Railscast #151 http://railscasts.com/episodes/151-rack-middleware).
We’re going to use Rack Middleware to overcome this issue.
Start by creating a ‘middleware’ folder under app.
Make the app aware of the new folder by adding the following to config/environment.rb

%w(middleware).each do |dir|
  config.load_paths << "#{RAILS_ROOT}/app/#{dir}"
end

Create a file called ‘flash_session_cookie_middleware.rb’ in the new middleware folder and add the
following lines:

require 'rack/utils'

class FlashSessionCookieMiddleware
  def initialize(app, session_key = '_session_id')
    @app = app
    @session_key = session_key
  end

  def call(env)
    if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
      req = Rack::Request.new(env)
      env['HTTP_COOKIE'] = "#{@session_key}=#{req.params[@session_key]}".freeze unless req.params[@session_key].nil?
    end

    @app.call(env)
  end
end

Unfortunately, documentation and examples relating Rack in the Rails world are a bit thin on the ground. See
http://rack.rubyforge.org/doc/Rack/Request.html for information relating to the Rack::Request.new in the above. A call from uploadify will satisfy the ‘if’ condition above, and the cookie will be modified as a result.
In config/initializers/session_store.rb, add this (this is all one line) to insert the modification so that the
controller receives it:

ActionController::Dispatcher.middleware.insert_before
(ActionController::Session::CookieStore, FlashSessionCookieMiddleware,
ActionController::Base.session_options[:key])

(Credit due to to Timmy Crawford (link now defunct) for the above code).
We’ve changed some of the startup files, so stop and restart the server to make the changes stick. Running the app now and trying to upload will still cause an error (as we’ve still work to do!) but you should see a reference to the app/middleware/flash_session_cookie_middleware file, so we know it’s being called.
The question is – how do we use it?
One of the unused properties in the uploadify() function is called ‘scriptData’ which is ‘An object containing name/value pairs of additional information you would like sent to the upload script. {‘name’: ‘value’}’.
We can use this by editing the _show partial: (The italic text are changes)

<%- session_key_name = ActionController::Base.session_options[:key] -%>
<%= javascript_include_tag "uploadify/swfobject" %>
<%= javascript_include_tag "uploadify/jquery.uploadify.v2.1.0.js" %>

<script type="text/javascript" charset="utf-8">

  $(document).ready(function() {
    $('#upload_photo').click(function(event){
      event.preventDefault();
    });
  $('#upload_photo').uploadify({
    'uploader' : '/javascripts/uploadify/uploadify.swf',
    'script' : '/uploads/create',
    'multi' : true,
    'cancelImg' : '/images/cancel.png',
    'scriptData': {
      '<%= session_key_name %>' : encodeURIComponent('<%= u cookies[session_key_name] %>'), 'authenticity_token' : encodeURIComponent('<%= u form_authenticity_token if protect_against_forgery? %>')}
    });
  $('#upload_submit').click(function(event){
    event.preventDefault();
    $('#upload_photo').uploadifyUpload();
    });
  });
</script>

(The encodeURIComponent used above is a core javascript function that escapes characters.)
Note that we could bake the session name in, but in the cause of making our code less brittle, the session named is defined by the first line as shown. Note also, the check to see if protect_against_forgery is enabled, again in the cause of making the code less brittle.
Run the app now and try to save uploads – you’ll see that while we still get an error, the Authenticity issue has gone away.
You might want to check your database, because we’ll have been saving some null records so far – zero the
database.
We’ll now address the issue of the params hash being in the incorrect format for Rails to deal with.
Rails is expecting the data packed into a params[:upload] hash and it isn’t coming back from uploadify in
the correct form. The first issue is that the user_id isn’t even being returned, so we’ll add another line to the
scriptData properties in the _show partial (don’t forget to put a comma at the end of the authenticity_token line):
'user_id' : '<%= @user.id %>'
If you check the development log by trying to upload, you’ll see the user_id is now passed, although not in the correct form.
We need to coerce the parameters into the form that Rails wants to play with, so make sure the beginning of the uploads_controller/create action reads as follows:

newparams = coerce(params)
@upload = Upload.new(newparams[:upload])

and add a private method to the uploads controller. This will check to see if the params[:upload] hash
exists; if it does not, then the call is from uploadify and the params[:upload] hash is constructed and
passed back. If params[:upload] does exist then the method returns it.

private
  def coerce(params)
    if params[:upload].nil?
      h = Hash.new
      h[:upload] = Hash.new
      h[:upload][:user_id] = params[:user_id]
      h[:upload][:photo] = params[:Filedata]
      h
    else
      params
    end
  end

If you’ve been checking the database, you’ll see that the content type for the file is being incorrectly reported as ‘application/octet-stream’. We can change that by using the mime-types gem (which we installed at the beginning but haven’t used yet).
Add (one line)

params[:upload][:photo].content_type = MIME::Types.type_for(params[:upload][:photo].original_filename).to_s

to the coerce method

def coerce(params)
  if params[:upload].nil?
    h = Hash.new
    h[:upload] = Hash.new
    h[:upload][:user_id] = params[:user_id]
    h[:upload][:photo] = params[:Filedata]
    h[:upload][:photo].content_type = MIME::Types.type_for(h[:upload][:photo].original_filename).to_s
    h
  else
    params
  end
end

(I think the above really lives in the model, but to keep focussed on the issue…)
If you try uploading files now, you’ll still see HTTP errors being reported by uploadify in the browser, but a look at the database will show us that the files are being correctly reported to the database (including the mime-type) and a check of public/system shows us that the files are being stored in the default location.
What we haven’t done is amend the uploads_controller to use a respond_to block: after all, we’re using
javascript, right?
Rails decides what format to use in the respond_to block depending on the value of format in the request.
If you add a debugger after the flash[:notice] line in uploader_controller/create you can inspect the value that is being submitted for this by querying
@_request.format.to_sym
If you do this, you will see ‘:multipart_form’, which needs changing. To do so, we can add yet another line to the scriptData properties in the uploadify call the in _show partial. Let’s try javascript; we could then write a short script that would update the show view with the new number of photos and append the image to the list being displayed.
So … the scriptData property should now look like this:

{ '' : encodeURIComponent(''),
'authenticity_token' : encodeURIComponent(''),
'user_id' : '',
‘format‘ : ‘js’ }

If you try that and use the debugger in the uploads_controller you’ll see that, indeed,

@_request.format.to_sym => :js

Now we’ll edit the create action to respond to the js request. In the uploads_controller create method, replace the
redirect_to @upload.user
with

respond_to do |format|
  format.html {redirect_to @upload.user}
  format.js {render :js => "alert('Uploadify');" }
end

and try the app to test it. (Don’t forget to get rid of the debugger if it’s still there).
You will see in the development.log that the create function has indeed been called twice and the database will show that the uploads have been applied. Unfortunately, as no alert appears, the format.js didn’t fire.
Going back to the uploadify documentation, we see that one of the uploadify() properties is a function call by the name of onComplete that triggers after each file upload. The onComplete() function receives four arguments, one of which is ‘response’, which is the response from the server.
If we change our format from :js to :json, we can send what we want back to the browser.
Change the

‘format’ : ‘js’

to

‘format’ : ‘json’

in the scriptData property list in the _show partial and change the

format.js {render :js => "alert('Uploadify');" }

line in the uploads_controller create method to

format.json { render :json => { :result => 'success', :upload => upload_path(@upload) } }

As onComplete is called after each file upload, the ‘response’ property in the call will then be set to whatever
{ :result => 'success', :upload => upload_path(@upload) } } evaluates as.
We’ll use console.log to check that the browser is receiving the correct information. (Console.log works with Safari if you enable the debug features and with Firefox through Firebug. If you develop for the web, I highly recommend using Firefox with Firebug).
_show.html.erb should now look like this:

<%- session_key_name = ActionController::Base.session_options[:key] -%>
<%= javascript_include_tag "uploadify/swfobject" %>
<%= javascript_include_tag "uploadify/jquery.uploadify.v2.1.0.js" %><script type="text/javascript" charset="utf-8">
  $(document).ready(function() {
    $('#upload_photo').click(function(event){
      event.preventDefault();
    });
  $('#upload_photo').uploadify({
    'uploader'  : '/javascripts/uploadify/uploadify.swf',
    'script'    : '/uploads/create',
    'multi'     : true,
    'cancelImg' : '/images/cancel.png',
    onComplete  : function(event, queueID, fileObj, response, data) { console.log(response);},
    'scriptData': {
      'format'    : 'json',
      '<%= session_key_name %>' : encodeURIComponent('<%= u cookies[session_key_name]
%>'), 'authenticity_token' : encodeURIComponent('<%= u form_authenticity_token if protect_against_forgery? %>'),
      'user_id' : '<%= @user.id %>'
      }
    });
  $('#upload_submit').click(function(event){
    event.preventDefault();
  $('#upload_photo').uploadifyUpload();
  });
});
</script>

and if you try to upload again, with Firebug enabled, you’ll see
{"upload":"/uploads/38","result":"success"}
in the Firebug console. There should be one of these lines for each file you uploaded and the number (“38” here) represents the id of the filedata in the uploads table.
Now ‘/uploads/38’ should route us to the show method in uploads_controller for the record with id = 38 if we can get the javascript to run it. jQuery has a function called getScript that will do just that, so let’s see what happens. As the response is in JSON format, we need to convert it to a javascript value, so change the onComplete line to read

onComplete : function(event, queueID, fileObj, response, data) { var dat = eval('(' +
response + ')');$.getScript(dat.upload);},

Try uploading again and you will see from the development.log that the show action is indeed being called, although it is failing. The call is a javascript call ( you can verify this by using the debugger and checking the value of @_request.format.to_sym, which will show you that this is a :js request.
Now we’re finally in a position to update the browser using some javascript.
You don’t need to add a respond_to block to the uploads_controller/show method as it is looking for a js.erb file and we can provide one.
If you’ve followed this so far, you’ll know that we want to update the number of uploads in the view, and append the new upload to those displayed.
Updating the number requires a knowledge of the total number of uploads in the database, so edit the show method in uploads_controller to look like:

@upload = Upload.find(params[:id], :include => :user)
@total_uploads = Upload.find(:all, :conditions => { :user_id => @upload.user.id})

and add the following to a show.js.erb file created in app/views/uploads.

$('#photos_count').html('<%= pluralize(@total_uploads.count, "Photo") %>');

This uses jQuery’s html function to replace the contains of the div called photos_count
To append the new upload to the list, add the line

$('#uploads').append("<%= escape_javascript(render(:partial => "uploads/upload")) %>");

to the show.js.erb file.
I got a deprecation warning here:

DEPRECATION WARNING: @upload will no longer be implicitly assigned to upload. (called
from _run_erb_app47views47uploads47_upload46html46erb_locals_object_upload at /Users/
martin/work/rails_apps/uploader/app/views/uploads/_upload.html.erb:2)

So edit the append line we just added to:

$('#uploads').append("<%= escape_javascript(render(:partial => "uploads/upload", :locals
=> {:upload => @upload})) %>");

You should now be able to upload files successfully and see the users/show page updated as you do it.
What I’ve show is well short of a functioning application of course, but I hope it makes the steps required to make uploadify work with paperclip and rails clear.
Thanks are due to Ryan Bates for his never ending stream of top class Railscasts (http://railscasts.com); to Peter Kordel (http://pkordel.wordpress.com) for getting me thinking along the right lines in the first place.

Example code for the above can be found at https://github.com/martinhawkins/Uploadify-with-Paperclip-on-Rails-example/