February 12, 2006

Removing "public" From the URL of Rails Apps

Or... "How to get Ruby on Rails running on 34sp.com."

One of the challenges of running my own business has been keeping on top of the multitude of things I have to get done. David Allen's book Getting Things Done (or GTD) has been a very useful guide in this particular area, and I've been slowly developing my own to-do list web application to help me to put GTD into practice.

It's also given me a chance to try out Ruby on Rails, the web development framework darling of Web 2.0. And I can see why it's been getting so much hype - it's very quick to get something up and running, which you can then start to tweak and extend; the documentation is pretty well laid out, so I've found it much easier to delve into than, say, when I started learning PHP; and the built-in AJAX support, and layout system lend themselves well to rapid development of web apps.

One thing I have had a bit of trouble with is deploying my Rails app on my existing webspace. The standard directory structure for Rails maps the web app root into a directory called "public" and if you aren't going to have your app sit at the root of the website (i.e. http://www.myserver.com/), you seem to end up with an unnecessary "/public" in your URLs. For example, I want my todo-list to live at http://www.mcqn.com/tedium/ but by default it would actually be at http://www.mcqn.com/tedium/public/.

This is how I've worked round it on an Apache 1.3 server using fastcgi. I don't make any claims or guarantees for the information other than it seems to work for me. If there's a better way of doing this, or if there are problems with this approach, I'd love to hear about them, as then I can improve my web app and these instructions.

First off, a quick note about Ruby on Rails support with 34sp.com. They are only just starting to roll out Rails support on their servers, but were very helpful in getting it up and running on my server when I asked. This thread seems to be the place to check first to see what the latest status is for Ruby on Rails support at 34sp.com.

Assuming your web server root directory is called httpdocs (as mine is) and the place you want you've generated the Rails app in a directory called tedium (as I have), your directory structure should look something like this:


httpdocs/
tedium/
app/
config/
doc/
lib/
log/
public/
images/
javascripts/
stylesheets/
script/

Out of the box you should be able to point your browser at http://www.yourserver.com/tedium/public/ and be presented with your Rails app. http://www.yourserver.com/tedium/ would be nicer though.

HowToUseRailsWithRewrittenURLs in Ruby on Rails explains how to have your web server automatically redirect people, so if you went to http://www.yourserver.com/tedium/ it would automatically take you to http://www.yourserver.com/tedium/public/, but I don't think that's good enough. I want my URLs to be as clean as possible.

So what I did was to copy the fastcgi dispatcher scripts (that's dispatch.cgi, dispatch.fcgi, and dispatch.rb) and the .htaccess file from /httpdocs/tedium/public/ into /httpdocs/tedium. Then I had to edit the dispatcher scripts so that they could still find the environment directory. In each file, change the string "/../config/environment" into "/config/environment".

That should get most of your Rails app working at the new location of http://www.yourserver.com/tedium/, but it won't be able to find any images, javascript files or stylesheets as they're still in public. We can fix that with some mod_rewrite instructions in the .htaccess file.

I uncommented the RewriteBase line, and changed it to my directory name - in this case tedium:

#RewriteBase /myrailsapp

became:

RewriteBase /tedium

Then I added a new rewrite rule. This checks to see if the requested file exists in the public directory - if it does then the URL gets rewritten to include public, otherwise we let Ruby on Rails deal with it. So our final step changes:

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

in the .htaccess file into:

# See if this is a file in "public", and if it is, just redirect to it
RewriteCond /path/to/your/httpdocs/tedium/public/$1 -f
RewriteRule ^(.+) public/$1 [L]
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
# Otherwise, if this request isn't just for an existing file, give it to
# the Ruby on Rails dispatcher
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

Now you should be up and running with your new Rails app at its clean new URL. Hope that's helped.

Posted by Adrian at February 12, 2006 08:52 PM | TrackBack

This blog post is on the personal blog of Adrian McEwen. If you want to explore the site a bit further, it might be worth having a look at the most recent entries or look through the archives or categories over on the left.

You can receive updates whenever a new post is written by subscribing to the recent posts RSS feed or

Comments

Hi,

Great article. Just wondering if your links in your Rails app (using link_to) appear with the public still in? I've tried to adapt your method slightly to also remove /myrailsapp so that / is the start of my rails app.

I've modified all the paths accordingly but I'm now getting links as /myrailsapp/public/blog/show/1, for example and one or two are even linking incorrectly with :id.:format on the end. I guess its a routes.rb issue, but I can't figure it out.

Posted by: James Howard at June 22, 2007 05:22 PM

Hi James,

Sorry for the delay in replying, you caught me in the middle of moving country :-)

I've just checked some of the places where links get created in my app (using link_to and image_tag), and neither of them have "public" in the URLs anywhere.

Where are the dispatch.* scripts living in your installation? I think the URLs created by link_to, etc. are all relative to the location of the dispatch script (and /myrailsapp/public is the default location for the dispatch scripts). My guess is that you're redirecting the "/" URL to the "/myrailsapp/public/dispatch.fcgi" rather than "/myrailsapp/dispatch.fcgi". /myrailsapp/dispatch.fcgi doesn't exist on the standard Rails install - I just copied the one from public and changed the line in it where it "require"s the environment so that the new path was correct.

HTH,

Adrian.

Posted by: Adrian at July 11, 2007 10:45 AM

I'm also trying to remove the public part of the URL and have hit some problems. I've set up the rails skeleton in /httpdocs/ and it works fine when going to /public/. I've modified the dispatch.* files and placed them in /httpdocs/ and copied in .htaccess (I haven't done the mod_rewrite changed yet).

However, when I now go to / after a while I get an Error 500 because the rails application couldn't start. I can't see anything in the logs about why.

Any help is appreciated.

Posted by: Michael Smith at September 17, 2007 11:43 AM

Do you still get a 500 error if you retry the page straight away?

When you get those sorts of crashes, it usually generates a log in RAILS_ROOT/log/fastcgi.crash.log rather than the usual log file.

I did sometimes get 500 errors because the dispatch.fcgi had given up waiting before rails had had chance to start, but if I reloaded the page straight away rails would have started and the subsequent request would succeed.

That was a separate problem that I ended up having to tweak the dispatch.fcgi to fix.

Posted by: Adrian at September 18, 2007 08:20 AM

I know this is an old topic, but I really need your help with this stuff...

34SP.com have set up Passenger now so that Rails runs better with Apache, which is great!

I want to do the same as you have here, but don't know if I can use the dispatch.rb script with Passenger. Would you know if it's possible?

Posted by: John Porter at November 23, 2010 07:26 PM
Post a comment









Remember personal info?





Note: I'm running the MT-Keystrokes plugin to filter out spam comments, which unfortunately means you have to have Javascript turned on to be able to comment.