BarCamp Nashville 09 Presentation - Symfony vs Rails
OCT
28
2009
Brent Shaffer and I gave a presentation at the 2009 Nashville BarCamp titled "Test Your Might - Framework Combat" comparing Ruby/Rails with PHP/Symfony. Below is a copy of the slides we presented.
Rails Subdomain Caching
OCT
02
2009
A while ago, I was working on a site that had dynamic subdomains based on cities in the database. For example, if an admin created a record for Nashville, it would create http://nashville.sitename.com. The site was pretty content heavy, but didn't change a whole lot, so I wanted to cache as much as I could. The problem with caching was that the content of each page depended on the subdomain. I couldn't use the normal caching strategy because of this.
To handle the subdomain routing and identification, I used the awesome subdomain-fu plugin (which worked great). Subdomain-fu, however, does not do the work of putting your cached files into folders named for your subdomain. Luckily, fixing this was as easy as adding a before filter to my ApplicationController.
class ApplicationController < ActionController::Base
before_filter :update_cache_location
def update_cache_location
if current_subdomain.nil?
ActionController::Base.page_cache_directory = "#{RAILS_ROOT}/public/cache/"
else
ActionController::Base.page_cache_directory = "#{RAILS_ROOT}/public/cache/#{current_subdomain}/"
end
end
end
That method will update the page_cache_directory value to be your current subdomain (or default if you are on the main domain). Now, this takes care of one problem, but how the hell do we retrieve the cached files? I had a little bit of trouble with this, mainly because I'm not a mod_rewrite specialist. After some tinkering and testing, I finally came up with the following rules to put in my conf file to properly retrieve the cached files based on the subdomain.
# Check for subdomain cached index
RewriteCond %{HTTP_HOST} !^www\.sitename\.com
RewriteCond %{HTTP_HOST} ^([^.]+)\.sitename\.com
RewriteRule ^/$ /cache/%1/index.html [QSA]
# Check for subdomain cached page
RewriteCond %{HTTP_HOST} !^www\.sitename\.com
RewriteCond %{HTTP_HOST} ^([^.]+)\.sitename\.com
RewriteRule ^([^.]+)$ /cache/%1/$1.html [QSA]
# Check for regular non-subdomain index
RewriteRule ^/$ /cache/index.html [QSA]
# Check for regular non-subdomain page
RewriteRule ^([^.]+)$ /cache/$1.html [QSA]
Those first two entries check to make sure the subdomain isn't www, then checks the cache folder for a cached version of the page. The last two entries check for the regular www subdomain.
These entries worked great for my project, but, like I said, I'm no expert with mod_rewrite. If you see anything that can be simplified or a better way of doing something, please let me know in the comments.
CentOS Setup Script with Ruby, Apache, mySQL, Subverion, Git, Passenger, and ImageMagick
AUG
31
2009
Recently, I participated in the Rails Rumble competition. If you've never heard of the Rails Rumble, it's a 48-hour coding contest where teams of 4 programmers/designers have to complete a fully-working application over the course of a weekend.
Linode, one of the sponsors, provided each team with virtual private server to host their application. This was great, but the servers were bare-bones and required a fair amount of setup. Knowing this in advance, I hoped to save some time by writing a script that would automate the process for our team so I didn't have to spend 30-45 minutes just trying to configure the server.
Here are the steps I took to get Ruby, Apache, mySQL, Subversion, Git, Passenger, and ImageMagick set up on our CentOS server.
Step 1: Add custom repository listing
The default CentOS repo only has Ruby 1.8.6. While there's nothing wrong with this, I wanted to get 1.8.7. To do that, copy the following text into a file called /etc/yum.repos.d/rubyworks.repo:
[rubyworks] name=RubyWorks baseurl=http://rubyworks.rubyforge.org/redhat/$releasever/RPMS/$basearch enabled=1 gpgcheck=1 gpgkey=http://rubyworks.rubyforge.org/RubyWorks.GPG.key priority=1
Step 2: Bash script
The only other step is to copy the following bash script to a file (called anything you'd like), chmod it to be executable, and just run it as root (very important!). It's magic!
#!/bin/bash # You must run as sudo!!!!! # update package list yum update -y # get all the packages required for compiling source yum groupinstall 'Development Tools' -y # install apache yum install httpd mod_ssl -y # install mySQL yum --enablerepo=rubyworks install mysql-server mysql mysql-devel mysql-ruby -y # set mysql and apache to start on boot /sbin/chkconfig httpd on /sbin/chkconfig --add mysqld /sbin/chkconfig mysqld on /sbin/service httpd start /sbin/service mysqld start # install postfix and subversion yum install postfix subversion -y # install git and dependencies yum install gettext-devel expat-devel curl-devel zlib-devel openssl-devel -y wget http://kernel.org/pub/software/scm/git/git-1.6.4.2.tar.gz tar zxvf git-1.6.4.2.tar.gz cd git-1.6.4.2 make prefix=/usr/local all sudo make prefix=/usr/local install cd .. # install ruby yum install --enablerepo=rubyworks ruby ruby-devel ruby-irb ruby-rdoc ruby-ri # install ImageMagick and all of it's required packages yum install tcl-devel libpng-devel libjpeg-devel ghostscript-devel bzip2-devel freetype-devel libtiff-devel -y wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz tar zxvf ImageMagick.tar.gz cd ImageMagick-* ./configure --prefix=/usr --with-bzlib=yes --with-fontconfig=yes --with-freetype=yes --with-gslib=yes --with-gvc=yes --with-jpeg=yes --with-jp2=yes --with-png=yes --with-tiff=yes make clean make make install cd .. # get rubygems wget http://rubyforge.org/frs/download.php/57643/rubygems-1.3.4.tgz tar xvzf rubygems-1.3.4.tgz cd rubygems-1.3.4 ruby setup.rb cd .. # install rails gem install rails --no-rdoc --no-ri # install rmagick gem install rmagick --no-rdoc --no-ri # install mysql gem gem install mysql --with-mysql-config=/usr/bin/mysql_config --no-ri --no-rdoc # install passenger and apache module gem install passenger --no-ri --no-rdoc passenger-install-apache2-module
DISCLAIMER: This worked great for me on a Linode 360 running CentOS 5.2. If you have any additions or changes, leave them in the comments and I'll be sure to add them. You can also get the entire script in a gist here.
Ruby Script to Add Apache Virtual Host Entry
AUG
10
2009
When you're working with Rails, you never really have to add a virtual host entry for development (unless you use Passenger). You can always just fire up script/server and navigate to http://localhost:3000.
At my new job, I'm doing a lot of work on PHP and Drupal sites, which require you to add an entry to your host file and add a virtual host conf file for Apache. After only going through this process twice, I was already tired of it. I wrote the following script to automate the process for me.
#!/usr/bin/ruby
########################################
##### VARIABLES YOU NEED TO CHANGE #####
########################################
host_dir = '/etc/hosts' # path to your hosts file
sites_dir = '/Library/Webserver' # path to the directory where you keep your sites (NO TRAILING SLASH!!!)
conf_dir = '/etc/apache2/sites' # path to directory where named conf files live
########################################
unless ARGV[0]
puts "Usage: add_site sitename [hostname_for_url]"
puts "Example: add_site sample sample.dev"
exit
end
name = ARGV[0].strip
hostname = ARGV[1].nil? ? ARGV[0] : ARGV[1].strip
# first things first: make sure named conf file doesn't exist already
if File.exists?("#{conf_dir}/#{name}.conf")
puts "Conf file named #{name}.conf already exists!"
exit
end
# check to make sure host file exists
if File.exists?(host_dir)
puts "Adding entry to #{host_dir}."
File.open(host_dir, 'a') do |host_file|
# append host entry to end of file
host_file.puts "127.0.0.1\t#{hostname}"
end
puts "Host entry added!"
puts "Adding named conf file."
File.open("#{conf_dir}/#{name}.conf", 'a') do |host_file|
# add entry
host_file.puts <<EOF
<VirtualHost *:80>
ServerName #{hostname}
DocumentRoot "#{sites_dir}/#{name}"
DirectoryIndex index.php
<Directory "#{sites_dir}/#{name}">
Options FollowSymLinks MultiViews Includes
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
EOF
end
puts "Conf entry added!\n"
puts "Restarting apache.\n"
system "apachectl graceful"
puts "Done!"
end
What you need to do to get this to work:
- Change the variables at the top of the file (path to your hosts file, path to the folder where you keep your development site, and path to the directory where you want to keep your named conf files).
- Rename the file to add_site(with no extension) and move to your /usr/bin directory.
- Chmod the file to be executable.
Now you can run the add_site command and provide it with the name of the site folder and optionally the name of the local domain you'd like to use.
Rails DELETE requests with JQuery
MAY
20
2009
When I write admin controls for for a Rails app, I like to make the delete links just fire off an Ajax request, delete the record, and remove the element from the page. This is easy with the Rails default setup using Prototype. All you have to do is use link_to_remote with a :method => 'delete' to make Rails do all the work. The problem is, this is the code that Rails generates:
<%= link_to_remote("Delete", :url => admin_post_path(post), :method => :delete) %>
<!- turns into: -->
<a href="#" onclick="new Ajax.Request('/users/63', {asynchronous:true, evalScripts:true, method:'delete'});); return false;">Delete</a>
While this isn't terrible, it's certainly not very pretty. Surely we can make the code cleaner and simpler!
Well, we've recently switched to using JQuery for all of our new apps at Plexus. Unless you use the JRails plugin, the link_to_remote helper no longer works when using JQuery. I figured this would be a good time to switch the remote calls to be handled separately by JavaScript, instead of spitting out a ton of script in the HTML.
It's easy to just hijack links via JavaScript and have them submit via Ajax, but how do we handle REST requests that require the DELETE method?
I decided to just add a specific class to all links that I wanted to be hijacked by JavaScript, then add the code in my js file to handle the links with Ajax. My DELETE links would look like this:
<!- Link that uses DELETE method --> <%= link_to 'Delete', entry_path(entry), :class => 'remote-delete' %>
The key to hijacking the link is to include the hidden _method attribute set to 'delete'. My JavaScript to hijack the link would look like this:
$(document).ready(function() {
$('a.remote-delete').click(function() {
// we just need to add the key/value pair for the DELETE method
// as the second argument to the JQuery $.post() call
$.post(this.href, { _method: 'delete' }, null, "script");
return false;
});
});
This converts every link that has the remote-delete class to an Ajax request with the DELETE method!
Popular Posts
Search
Tags
actionmailer activerecord ajax apache apple barcamp caching capistrano centos code golf css db delete eager loading ebay email attachment erb flash ftp fun generators get haml helpers ie sucks javascript jquery lightbox lost merb net ftp paperclip passenger php plexus post presentation rails rails machine railsconf redesign rest rjs routes rss ruby ruby on rails safari script sinatra symfony text replacement tips tutorial twitter xhtml
Projects
© 2010 Travis Roberts. All rights reserved.