Posted November 19th, 2008
Here's a quick snippet I use for quickly disabling chunks of view code.
To use this, just drop the following into your application helper:
Of course, you could just surround your code with <% if false %><% end %> but I think using this simple helper makes the intent slightly clearer.
Posted November 16th, 2008
The generally accepted pattern for the new/create actions of RESTful Rails controllers goes something like this (using Recipes as the model):
The actions for edit/update are fairly similar so I won't show them here. I've also ignored XML responses as they aren't relevant here.
So what is wrong with this? Lets imagine we're filling out the new recipe form, hence our current path looks like /recipes/new. The form is then posted to /recipes and the @recipe.save call fails due to validation errors in our Recipe model. What is the current path now?
Where we end up is viewing the same form previously accessed at /recipes/new, but now at the path /recipes. Having two URLs accessing the same view, whilst not a major cause for alarm, emits an unpleasant odor.
In recent projects, I have taken to the following alternative pattern:
The changes are small but we are now using the session to store the invalid object. If the object fails to save, we redirect back to the new recipe form (at the correct path /recipes/new), which attempts to load the recipe from the session, otherwise defaulting to the original behavior.
Using the session in this way has one big drawback -- we can no longer reliably use the default Rails cookie session store. There are two main reasons for this: a) Cookie stores have a storage limit of 4k, which can easily be reached when storing large objects in the session -- you'll end up with CookieOverflow exceptions being thrown; and b) Saving an object in the cookie store sends the entire object to the client, potentially exposing hidden data. Because of this, I choose to use the memcached session store (which is almost trivially easy to set up unless you're on a shared host).
This approach also appears to add some complexity, but in some ways its behavior is clearer. Consider the case in the original example where we want to add an error message to the flash:
BZZZT! What we actually need to use here is flash.now[:error] rather than flash[:error] because we want to render the error within the same action. This gotcha doesn't exist in my alternative version.
So what do you think? Are there any use cases apart from those mentioned where this is either going to fail or cause security issues? Is it even worth using this pattern to fix the original problem, despite the caveats? I think so but I'm willing to be proven wrong.
Posted May 15th, 2008
At Good Dog Design, we manage a number of servers for our clients,
and are frequently adding new ones. Whilst this process should really
be scripted, until we do, this checklist should help cut a lot of the
time that goes into setting up a new server.
These checklists are somewhat debian specific as we mainly run debian and ubuntu servers (on Slicehost if you’re curious), but many of the points can easily be adapted for your distro of choice.
Core server setup
- Reset root password
- Add a normal privilege (non-root) user
sudo adduser {username} - Add this user to sudoers
visudo - Login with this user
- Ensure all relevant security/update repositories are present in
/etc/apt/sources.list - Ensure all packages are up to date
sudo apt-get update; sudo apt-get upgrade. If any packages are kept back, install them individually sudo apt-get install {package-names}. - Install and configure a firewall
sudo apt-get install shorewall (see configuration at http://blog.matid.net/2007/2/1/securing-your-ubuntu-server [default config is located at /usr/share/doc/shorewall-common/default-config/] - Install essential build tools
sudo apt-get install build-essential
Services setup
- Install git
sudo apt-get install git-core or subversion sudo apt-get install subversion - Install ruby
sudo apt-get install ruby irb ri rdoc ruby1.8-dev libopenssl-ruby - Install rubygems from http://rubyforge.org/frs/?group_id=126 (don’t use apt-get)
- Link gem to gem1.8
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem - Install relevant gems
sudo gem install rails mongrel mongrel_cluster - Install postfix
sudo apt-get install postfix - Install mysql
sudo apt-get install mysql-server mysql-client libmysql-ruby1.8 - Create a production database and user
- Install memcache
sudo apt-get install memcached; sudo gem install memcache-client - Install apache
sudo apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-utils ssl-cert - Enable apache modules
sudo a2enmod proxy_balancer; sudo a2enmod proxy_http; sudo a2enmod rewrite; sudo a2enmod deflate - Create an apache host config file in
/etc/apache2/sites-available and enable it sudo a2ensite {sitename} - Create a deploy group
sudo groupadd deploy and add any users to this group (sudo adduser {user} deploy) - Create a folder for the project
sudo mkdir /var/www/project-url.com; sudo chown {me}:deploy /var/www/project-url.com - Create a mongrel user and group
sudo useradd mongrel (don’t set a password for this user) - Install and configure monit
sudo apt-get install monit
Rails setup
- Capify rails project
capify . - Install and configure the ExceptionNotifier plugin
- Install any app-specific gems
- Setup capistrano folder structure
cap deploy:setup - Cold deploy
cap deploy:cold - Ensure mongrels are running and site is accessible
- Test regular deploys
cap deploy - Setup any necessary cronjobs (I generally put them into an individual project file in
/etc/cron.d/) - Set up log rotation
Posted April 29th, 2008
After a long time away from the keyboard (so to speak), its about time I started blogging again!
Since I last blogged, I’ve completed my honours degree in Computer Science at the University of Adelaide and am now working for Good Dog Design in Mill Valley (about 15-20 minutes drive north of San Francisco).
This
site is under development at the moment but it should be up and running
very soon. My intentions are to blog about web dev related topics
(Ruby, Javascript, etc.) and whatever else takes my fancy.
Enjoy.