Feed on
Posts
Comments

Several months back I presented at WellRailed on using Memcache with Rails.  I focused on fragment caching and the libraries I’d created to make life easier.  I’ve now moved some of what I discussed into a plugin available at github which I’ve described as follows:

A enhanced version of and replacement for the MemCacheStore shipping with rails.  It uses a per-request local cache to buffer duplicate memcache reads which can result in halving read requests, and it uses a single connection to memcache for both the cache and session stores.

It doesn’t yet have the awesome key creation and maintenance library that I showed as that has evolved quite a bit and needs a big bunch of love first - which I’m working on.

There is now a dedicated page on this site for the plugin, currently it’s holds a copy of the plugin’s README.  My intention is to update the page with examples etc.. as I extend the plugin.

I was upgrading a client’s application to Rails 2.1.2 from 2.0.x the other day, this resulted in refreshing a number of gems and plugins including will_paginate and attachment_fu.  In doing so I found a stupid problem that I couldn’t find anything about online - it’s a pretty one off unique case so I thought I’d blog about it to help the next person.  ‘Pay it forward’ I guess.

The problem was this: somewhere along the line attachment_fu was updated to execute the following line of code on classes using the has_attachment directive:

attr_accessible :uploaded_data

This is taking advantage of a security feature in Rails, it instructs the model to only allow :uploaded_data to be set through update_attributes and any like methods such as new and create.  So whitelisting bulk settable attributes.  It doesn’t raise any errors, just warnings in your log like this:

WARNING: Can't mass-assign these protected attributes: <attribute_name>

Due to no errors being raised the problem was presenting itself in other parts of the application as expected data was not being found.  Fortunately I was tailing my dev log and noticed the above warning message.

The problem in this situation was the historic code creating instances of the model by passing a hash through to SomeModel.create.  As this area of code was not utilising data posted to an action it was not a security risk.  Very fustrating, especially as this was common practice throughout the codebase.

As I didn’t want to do a huge bunch of re-keying my initial solution was to comment out the offending line in attachment_fu.  Yes this is a big nasty fix but there was time pressure, other problems to solve and I didn’t want to be held up having caused an unnecessary amount of manual testing.  In case it was forgotten about  and overriden with a future plugin update, a quick test with big comment was added.

This project hadn’t updated it’s gems and plugins for a while, meaning it was a big shock to the system when they where.  This was the biggest headache, all other problems were mainly just gem interfaces changing, so a easy search and replace matter.

I like passing a hash to mass-assign data in Rails as well as the obvious coding benefits it’s visually more readable too, but this is out weighed by my great dislike of having my sites hacked into.  So it’s a shame things have had to go this way.

Over the weekend I moved this blog from being hosted on my Dreamhost account to one of my 256mb Slicehost servers.

I’ve done this mainly to stop paying for hosting twice, but also because if I’m going to be talking about performance I can’t possibly have a slow blog and my options were limited with the Dreamhost account.

My immediate problem being that I wanted to move it straight to being served by Ngnix rather than Apache - not something that Wordpress is setup for.  After a bit of googling I found that someone had solved all the problems I was going to have for me!  This post has blow by blow instructions for setting up a wordpress blog on Slicehost and Ubuntu, I couldn’t have found anything better.

It worked exactly as advertised, but me being me I could help tweaking and updated the nginx site config to include expire header for static assets, like so:

server
  {
 
  listen   80;
  server_name www.motionstandingstill.com;
 
  root   <path_to_site>;
 
  access_log <custom_log_path>/access.log;
  error_log <custom_log_path>/error.log;
 
  location ~* i.+\.(css|js|jpg|jpeg|gif|png)$
    {
    expires      7d;
    }
 
  location /
    {
    index  index.php index.html;
 
    # Basic version of Wordpress parameters, supporting nice permalinks.
    # include /etc/nginx/conf/wordpress_params.regular;
    # Advanced version of Wordpress parameters supporting nice permalinks and WP Super Cache plugin
    include /etc/nginx/conf/wordpress_params.super_cache;
    }
 
  # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  location ~ \.php$
    {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    include /etc/nginx/conf/fastcgi_params;
    fastcgi_param SCRIPT_FILENAME <site_path>/public/$fastcgi_script_name;
    }
  } # server

Later I found someone had posted a different conf with easy support for multiple blogs, but I’ve not moved to using it as what I’ve got works.  What it also does is add the expire clause support like I have done above.

When moving this blog to Slicehost I initially set it up on a temp subdomain to make sure it was working sweet first and because I wanted to try out some different themes and play with a couple of other things.

I quickly discovered that as it was running on a different doman than it was configured for, Wordpress would redirect my browser to the correct domain meaning I couldn’t get into the new site.  Ugh.  So I had to whip out my sql skills and manually update the appropriate settings.

UPDATE wp_options SET option_value = 'http://temp.motionstandingstill.com' WHERE option_value = 'http://www.motionstandingstill.com';

I actually used a different domain name and explicitly updated two rows rather than the generic ‘where’ clause I have, but you get the idea.  This allowed me in which is what I wanted.

Then I took the opportunity to tidy up what plugins I’m using as I’d gotten a bit ‘plugin install happy’ when first setting the blog up.  As well as getting rid of unwanted plugins I installed two new plugins I’d recently found, the first a redirection plugin with regex support and the second a security checking plugin.

Once I’d got everything how I wanted it, just sticking with the same theme (the misty tree photo is mine), I grabbed a final db backup from Dreamhost and restored it on Slicehost then changed my DNS A record.

All in all, much easier than I thought it would going to be thanks to some helpful results from google. :-)

Update: Slicehost has been aquired by Rackspace.

A couple of months back we had Nigel talking at WellRailed about a Foreign Key Constraint plugin he uses with Rails and then just this week the topic was brought up again for me with a client.  I’ve found it’s something that pops up every now and again.  Given this is such a polarizing issue I thought I’d order my thoughts into a post explaining why I don’t use foreign key constraints, in particular cascading deletes.

For me the reasoning is distilled down to my programming style.

Pragmatism

When it comes down to it, what vital benefit does it give you over :dependent => :destroy or model validation?  Will this give you increased quality faster, quicker and cheaper?

Premature Optmisation

Basically don’t waste time optimising something that isn’t slow or is hardly used.  Rails is so slow that some fractional speedup on the DB isn’t really going to be noticeable by the end user.  Instead examine your site with NewRelic or FiveRuns and fix your bottleneck code - way more bang for your buck.

Data is Valuable

So don’t go around deleting it!  If a user wants to delete some data you should want to know why.  Looking at the data can aid in determining why without having to bug the user about it.  Yes there are occasions when this does need to happen, but they should be the exception to the rule and thus explicitly coded for.

Just mark a record as deleted and filter it out automatically, that’s easy enough to do with rails - way easier than any other language I’ve used before.  Better yet, search github and use someone else’s wheel.

Convention Over Configuration

Basically put, you do things the way that everyone else has done it.  Walk the well walked path so to speak’ and you won’t experience any bizzaro problems that someone else hasn’t already solved before you.  As you’ve created your app in a predictable way, someone else can easily come in and contribute to your project, or visa-versa and it makes the whole Rails community more accessible to you.

So in following the conventions and as you are not encouraged to use foreign key constraints, Rails isn’t expecting data to be deleted out from underneath it.

Don’t Repeat Yourself && Model View Controller

DRY is another of the core philosophies behind Rails - partials are a real good example of this especially when you start to think of them as essentially methods.  On top of the obvious ’speed to deliver’ benefits this concept provides, it also causes you to distill your code down to being more readable and accessible.  This ties in nicely with MVC principles as you then tend to group like logic together which is what MVC is all about.

Foreign key constraints are business logic as they describe and implement a behavior - “when you delete this record, also delete these other records over here”.  So why would you go and put some ‘important to know about’ business logic in an isolated and often hard to reach place?

Documentation

The one great thing I learned from Steve McConnell’s Code Complete was how to write comments, they should describe the intention of the code, rather then repeat the code.  This nicely ties in with the DRY principle.

I’m also a great believer in self documenting code, Rails and Ruby help heaps with this, and generally write comments to help simplify complex code.  Instead of my code being littered with redundant comments cluttering everything up, it just contains important ones as they are more likely to be read and updated when the code is next worked on.

If you use foreign key constraints in your DB you’ll likely end up documenting them (ie repeating them) somewhere more accessible, in the models being an obvious place.  That wouldn’t be because the business logic lives there would it?.  Have a think about that.

The Rails Way

Looking at the Convention over configuration, Don’t Repeat Yourself and Model View Controller concepts above - as much as Rails is a framework it’s also about a way of doing things.

Over the years I’ve seen a notable number of people, new to rails and these concepts, trying to make rails work their way - often with less than desirable results.  If you embrace Rails and it’s ‘way’ then it works beautifully and is a pure joy to use, rather than a frustrating experience.

For me

Coding is an art form and as such a creative process.  If something doesn’t look, or even feel right then it’s wrong.  In the end foreign key constraints on a web app just rub me up the wrong way.

I’ve changed my home server from Centos 5.1 (32bit) to Ubuntu Desktop 8.04 (64bit) due to the CentOS drive crashing - it was real old. As my server doesn’t actually have a screen when it’s carefully hidden away I initially enabled Remote Desktop for GUI access. This worked ok, although slightly sluggish, in conjunction with Chicken of the VNC running on my MacBook as the viewer.

Problems arose once I rebooted it without the monitor plugged in as it defaulted to 800×600 without any obvious way of controlling this. Things got real annoying though when I discovered that a number of dialogs are longer than 600 pixels and I couldn’t see half the windows. That’s a real basic thing which shouldn’t be wrong.

So I tried installing the VNC Server itself and running that with options specifying my desired resolution

sudo apt-get install vnc4server
vncserver :1 -geometry 1024x768 -depth 16

only to be presented with X11 rather than the Gnome Desktop Manager when I connected. Of note is that when you first run vncserver it’ll ask you for a password and setup a ~/.vnc folder to store that and an xstartup script.

After a bit of a google I found a helpful post showing how to configure and launch vncserver through xinetd as well as powering up GDM. Follow it exactly as it works a treat. It’s part of a thread titled HOWTO: Set up VNC Server with resumable sessions.

Logging in though reveled a new problem - the Gnome Theme Setting manager was constantly crashing and causing the current theme to continually be applied then dropped. I was given this error “there was an error starting the GNOME settings daemon“.

Turns out this is a recent problem with the 4.1.1 version of vnc4server and the fix has yet to be rolled into a package for Ubuntu. I found custom deb files with the latest version of vnc. Francesco Santini has helpfully copied across the compiled binaries from the latest vncserver 4.1.2 Fedora 9 packages, which have the fix, into has own i386 deb files for people to download and install - no help for my 64bit install of Ubuntu though.

I actually tried looking for the vnc source code, thinking I could just compile that directly, but that route started proving harder than I thought it should. So, I’ve ended following Francesco’s lead and copying out the binaries from the Fedora VNC x86_64 packages manually like this:

wget ftp://rpmfind.net/linux/fedora/updates/9/x86_64.newkey/vnc-server-4.1.2-31.fc9.x86_64.rpm
wget ftp://rpmfind.net/linux/fedora/updates/9/x86_64.newkey/vnc-libs-4.1.2-31.fc9.x86_64.rpm
 
rpm2cpio vnc-server-4.1.2-31.fc9.x86_64.rpm | cpio -dimv
rpm2cpio vnc-libs-4.1.2-31.fc9.x86_64.rpm | cpio -dimv

And then copy them over top of my existing vnc binaries like so:

sudo cp usr/bin/* /usr/bin
sudo cp usr/lib64/xorg/modules/extensions/libvnc.so /usr/lib64/xorg/modules/extensions
sudo cp usr/lib64/librfb.so.* /usr/lib64

If you don’t have ‘rpm2cpio’ you’ll have to install rpm itself, a bit unnecessary and self defeating sounding I know:

sudo apt-get install

I found the latest vnc-server and the vnc-libs Fedora 9 x86_64 packages on rpmfind.net.

After doing all that I seemed to have made the situation worse and was getting a connection denied error from my viewer. A but more hunting and the problem turned out to be that the Fedora binaries, Xvnc in particullar, were expecting the libcrypto package and for one of it’s binaries to be differently named. I figure that’s due to them being compiled for Fedora. The following sorted that problem:

sudo apt-get install libcrypto++7 libcrypto++-utils
sudo ln -snf /usr/lib/libcrypto.so.0.9.8 /usr/lib/libcrypto.so.7

From memory I don’t think vncserver had this problem, just Xvnc, making the issue a bit harder to diagnose as running vncserver manually allowed me to connect, but not with the GDM login.

Having done all that I can now login to GDM and don’t get the crazy theme errors anymore, plus it’s noticeably faster. Something I discovered is that Chicken of the VNC doesn’t disconnect when you close the viewer window - and thus you can’t reconnect until you have quit the application. A bit suck, but oh well.

During my travels I found that I could manually do what xinetd was doing with this command:

sudo vncserver :5 -geometry 1200x750 passwordFile=~/.vnc/passwd -query localhost -fp /usr/share/fonts/X11/misc

Additionally I discovered the ‘alien’ package which converts rpm files to deb, which might ultmately be an easier way to install the latest version of vncserver from Fedora while maintaining a single package system.

Older Posts »