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.

Tuesday, August 19, 2008

Adding a text editor to a rails app

In an app I am building I need to give the user the ability to create well fashioned html in an easy way.

My first attempt was to use the textile markup language, using the acts_as_textiled plugin. This was alright but requires that the users learn a markup language that is not completely intuitive. I also had to install the Redcloth gem, which I wasn't entirely sure would be easy to install on the platform I was deploying to. I decided to look for another option.

After reading this article I decided to opt for the tinyMCE option. This was mainly because on the demo widgEditor didn't seem to remember any picture resizing that went on. Following the instructions here I performed the following steps to get the editor working (mostly shamelessly copied from the instructions in the linked blog).

1. Download TinyMCE

2. Make a new folder in your rails app: ‘public/javascripts/tiny_mce’

3. Copy the contents of the ‘jscripts/tiny_mce’ folder from the download into this new folder in your rails app. (So now you should have a folder in your rails app: ‘public/javascripts/tiny_mce/’ which contains the ‘langs’, ‘plugins’ and ‘themes’ folders, amongst other things.)

4. Make a new file: ‘public/javascripts/mce_editor.js’ and add your TinyMCE initialisation code, e.g.

tinyMCE.init({
theme:"advanced",
mode:"textareas",
plugins : "safari",
...
});

(Get more information on the TinyMCE API and configuration options from the TinyMCE wiki)

As I wanted the TinyMCE editor to only apply to to a single text_area (on a page of several) I added the line "editor_selector: mce-editor", to select only text_areas with a css class = "mce-editor".

5. Add a method to the application helper

def use_tinymce
@content_for_tinymce = ""
content_for :tinymce do
javascript_include_tag "tiny_mce/tiny_mce"
end
@content_for_tinymce_init = ""
content_for :tinymce_init do
javascript_include_tag "mce_editor"
end
end


6. In the application layout (views/layouts/application.rhtml), yield the appropriate contents. According to this TinyMCE wiki page the order of javascript files is important.


<%= javascript_include_tag "prototype" %>
<%= yield :tinymce %>
<%= javascript_include_tag "scriptaculous" %>
<%= javascript_include_tag "effects" %>
<%= javascript_include_tag "controls" %>
<%= yield :tinymce_init %>



7. Now, to use tinymce in a view or layout, just make a call to the new helper method e.g.

<% use_tinymce -%>
<%= textarea_tag :foo, :bar, ... :class => "mce-editor" %>


8. Although TinyMCE does do some tidying up of the html code, you will also want to add white-listing to your implementation to prevent people submitting anything dodgy. (Note that for some of the more advanced TinyMCE formatting, you will need to allow the “style” attribute in your whitelist).

This was as simple as doing

script/plugin install http://svn.techno-weenie.net/projects/plugins/white_list/

and changing the html-enabled fields from

<%=h @band.description %>

to

<%= white_list @band.description %>

and restarting the webserver (!).

Monday, August 18, 2008

Setting up a rails app on Site5

This is an article describing how to set up a rails app on site5 with FCGI. It is just a basic set up. Hopefully a Capistrano deployment article will follow shortly.

First you need to set up the databases your application will use. Do this in the Backstage admin area. You will need the names of the databases later to put into your database.yml file.

You also need to have ssh access to the server. You might need to submit a support ticket to have this enabled. To see if you have ssh access attempt to log in: go to an ssh terminal (eg putty on windows or the standard terminal on mac/linux) and type

ssh user@yourdomain.com

If you have ssh access you should then be prompted on whether you want to recognise the site's key (if it is the first time you have visited it) and then for your password. On logging in you should be presented by a command line prompt in your terminal. This is how we are going to interact with the server to set up the app.

You then need to upload your app to the server. I used an FTP client for this and uploaded it into a file called "apps" in my home directory on the server.

Navigate into your app folder on the server:

cd ~/apps/myapp


Set the correct permissions on the application files (not sure if these are the best permissions to set, but it works):

chmod -R 755 myapp


The files dispatch.cgi, dispatch.fcgi and dispatch.rb in the myapp/public directory are somehow involved in loading the cgi/fcgi/rb processes for serving the web app. We need to tell these where to find ruby, which is different on the server to where it (probably) is on your local computer. Change the first line of each of these files to

#!/usr/bin/ruby


If you now navigate to the myapp/public file and run

./dispatch.fcgi

you should get the html associated with your application root (identified through map.root in config/roots.rb) spat into your terminal window.

Go to the myapp/config/environment.rb file and uncomment the

ENV['RAILS_ENV'] ||= 'production'

line, to put the rails app into production mode.

We also need a .htaccess file in the myapp/public directory to tell requests that get redirected to this directory to be handled by the fcgi process. This .htaccess file used to be generated by the rails scaffolding but, from rails 2.0.1 onwards, isn't anymore. I used the following .htaccess file taken from an earlier app:

# General Apache options
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI

# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]

# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On

# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp

RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html

ErrorDocument 500 "

Application error

Rails application failed to start properly"

Either upload this file using ftp or use a command line text editor (eg vi/nano/emacs) to create and save it.

We now need to provide a symlink so that users visiting yourdomain.com will be redirected to the public file in your app (and then dealt with via the fcgi handler) instead of just seeing whatever is in your ~/public_html folder. I did the following:

cd ~/public_html
ln -s ~/apps/myapp/public another_name_for_myapp

Note: it is important to use a different name as symlinks seem to get upset if you use names that are too similar.

We also need to have a .htaccess file in this folder to tell the web server to use the symlink. Upload/create the following file to the ~/public_html directory:

Options +FollowSymLinks +ExecCGI
RewriteEngine On


Now by visiting yourdomain.com/another_name_for_myapp you should be directed to the root of your application.

You will need to put your database settings into your database.yml file and then create and migrate your databases.