Mixing other languages into your Rails app for local development

For my current project, I thought it might be nice to offload a few Ajax calls onto something other than my app’s Ruby process – that can only handle one request at a time, and Ruby is notoriously slow, so I didn’t want to bog it down with some niche things that could take over a second to respond to. I decided to try having a few PHP scripts to handle such things, and it turned out that mixing PHP into my Rails app was not a easy as I might have liked.

Now, I’m on Windows (I’m a designer as well as a developer, and I need IE), so this guide will only work for that platform. Mac and Linux users, I’m sorry. Also, I know that one solution to this problem is to run multiple app instances and load-balance them, but I’m not hosted on an environment where I can access the Apache config. Besides, people may find other uses for this.

The Mongrel or WEBrick server that runs your app on your local machine won’t handle PHP scripts if you place them in, say, public/php. If you run with Apache as your production server that will work fine as long as you put the following in public/.htaccess:

# Let Apache handle PHP requests
RewriteCond %{REQUEST_URI} ^/php.*
RewriteRule .* - [L]

On your local machine, you’ll need to put your PHP scripts somewhere else and set up Apache so that they appear to be served from the same domain as your app so they work for Ajax calls. The first step is to open up C:\WINDOWS\system32\drivers\etc\hosts and add a host name for your project:

127.0.0.1       localhost
127.0.0.2       yourproject.local

On my machine, Apache is at C:\webserver\Apache2.2 and my Rails project is at C:\webserver\Rails\yourproject, so you’ll need to adjust for your setup. The first apache configuration you’ll need to do is in C:\webserver\Apache2.2\conf\httpd.conf. Make sure the following line is uncommented (i.e. there is no # at the beginning):

LoadModule alias_module modules/mod_alias.so

Then add the following at the end of the file:

<VirtualHost 127.0.0.2>
  DocumentRoot "C:/webserver/Apache2.2/htdocs/yourproject"
  ServerName yourproject.local
  ErrorLog logs/yourproject.log
</VirtualHost>

This means that, after you’ve restarted Apache, pointing your browser at http://yourproject.local/ will return files served from C:/webserver/Apache2.2/htdocs/yourproject. Notice the shared hostname and IP address between this file and the Windows hosts file.

Go ahead and create this folder, and create another folder within it called php (continuing my example). The final step in the process is to force Apache to proxy anothing other than requests for PHP files to the currently running Rails app server. To do this, add the following line at the end of C:\webserver\Apache2.2\conf\httpd.conf:

Include conf/httpd-proxy.conf

Create the file C:\webserver\Apache2.2\conf\httpd-proxy.conf and copy the following into it, adjusting for the name of your project:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyRequests Off

<Proxy *>
  Order allow,deny
  Allow from all
</Proxy>

<Directory "C:/webserver/Rails/yourproject/public">
  Options Indexes FollowSymLinks
  AllowOverride none
  Order allow,deny
  Allow from all
</Directory>

ProxyPass /php !
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/

The Directory sets some rules for your app’s public directory – edit these to your liking. The final three lines tell Apache not to proxy requests to the php directory, but to proxy all other requests to the address of your Rails development server. So, hitting http://yourproject.local (after restarting your Apache and Mongrel/WEBrick servers) will bring up your Rails app. All should function as normal, except that any request to http://yourproject.local/php/* will go to the directory containing your PHP scripts – C:/webserver/Apache2.2/htdocs/yourproject/php.

Note that this will affect all local domains your have set up, not just yourproject.local. If you want to work on anything else on your Apache server, you may need to comment out the final Include line in httpd.conf.

That’s a slightly roundabout guide, but getting this set up was really useful for me and hopefully you’ll get some mileage out of it.