Wednesday, August 20, 2008

Attachment_fu goes to index instead of create in production

I am using attachment_fu to allow image uploading in my application. In my development environment on my local machine everything worked fine. However, on the production server I would press 'create' on the upload image form and it would just list the images without showing my new image.

I had a look in the rails log (in myapp/logs/production.log) to see what was going on. I could see the request for the new controller, but this was followed directly by an index request. For some reason there was no create request.

After some digging about I found that this was to do with how the routes and the webserver were playing together.

Rails uses restful routes to decide which controller to call. If you go to the url 'myapp.com/images' with a GET request it calls the 'index' controller whereas with a POST request it will call the 'create' controller. Somehow the POSTness of my request was getting lost.

The reason for this was due to the way the apache handles its own routing (from http://www.ruby-forum.com/topic/103619):

When your form is created, the action is "/files". When this post
request hits the Grid, Apache sees that request (http://app.com/files)
and that there is a directory there, and so appends a slash (http://
app.com/files/) and redirects the browser to the new URL. This is
standard Apache behavior since most requests for a directory name are
usually for the directory's contents rather than the directory itself.
Since Apache does the redirect, the post turns into a get before your
Rails application even has a chance to see it. To test this out,
rename your files directory to any other name and you will see that
the post request starts working again.


So to fix the problem we need to fix the trailing slash issue. I found a few suggestions on how to do this.

In investigating each of these solutions I used the Net console provided by the Firebug firefox extension in order to view the requests as they left the browser and see if the trailing slash was present or not.

The first was to put the following inside the 'controllers/application.rb' class:

def default_url_options(options)
{ :trailing_slash => true }
end

This didn't seem to work for me. Not entirely sure why. It didn't cause a slash to be added and caused 'wrong number of arguments' errors on some of my routes.

The second was to put

DirectorySlash Off

in your .htaccess file on your server to stop apache appending the slash. I decided against this option as .htaccess files scare me a little.

Instead I set the trailing_slashes option only on the image submit form:

form_for(@image, :url => {:action => 'create', :trailing_slash => true}, :html => { :multipart => true })


This seemed to work.

No comments: