Slicehost
Posted on June 23, 2008
Filed Under Rails, Ruby, Web | Leave a Comment
I've been working with Rails now for nearly two years and for the majority of that time I've been working in environments where the hosting has already been worked out.
At Impact we used the excellent RailsMachine for our hosting. We had a cluster of 6 VPS' all with 256 Mb RAM and about 5 Gb of disk. Most of the Rails applications we we're running we're fairly low traffic (few hundred hits a day) and as we had plenty of capacity we ran one application per VPS with 2 or 3 mongrels and an Apache front end.
More recently at The Sanger Institute we've got a whole team of systems guys who are responsible for maintaining the server farms and on a couple of the nodes we have Rails installed. All of our applications are running a nginx front end proxying to a bunch of mongrels (between 5 - 10 per application). We've essentially got unlimited resources to use at Sanger and so apart from recompiling nginx so that instead of doing a round robin on the mongrel cluster if takes note of which mongrels are busy we've done very little to optimise our environment.
It's only recently that I've had to get serious about Rails hosting for my personal projects. Most recently I've been working on a conference organisation tool for some old colleagues of mine at The University of Nottingham. I've been with Mediatemple for about a year now but they're standard 64Mb RAM doesn't really cut it if you want to run anything more than one mongrel. Perhaps more worryingly, Matt tells me that if you start using more than your fair share of resources they kill you site!
So, after looking at a fair few options I've gone with Slicehost. Slicehost offer a service whereby you are allocated your own Xen-powered VPS with a choice of Linux distros. At $20 for 256 Mb RAM and 10 Gb of disk they're pretty good value and the only wrinkle is that they essentially give you a freshly installed Linux box with ssh installed and little else - you even have to install your own firewall! However, after about 2 hours of following the excellent tutorials written mostly by (presumably) Slicehost admin "PickledOnion", I had a streamlined Ubuntu box with Rails, Nginx and MySQL and Mongrel installed. And to be honest there's little else to say. It's basically just worked flawlessly ever since. The only extra configuration that I've made over a standard setup is that I'm using god to monitor the mongrels and ar_mailer to send batch emails.
Provided that you're comfortable enough on the command line to follow a few simple setup guides Slicehost have proved themselves to be a very cost effective custom Rails host.
History Meme
Posted on April 25, 2008
Filed Under Uncategorized | Leave a Comment
Seems that this history meme thing is pretty popular at the moment. So without further ado here's mine:
history | awk '{print $2}'| sort | uniq -c | sort -rn | head
103 ss
94 ls
61 svn
55 cd
43 cap
32 sc
19 mysql
18 apps
10 rake
9 seq1
I'd like to make it clear that even though my top hit is a common name for a certain military organisation under the command of a certain fascist dictator, on my MacBook it's a bash alias for
./script/server
That it, for starting Rails apps. I also have sc for starting the Rails console. Anyway, pretty good I reckon. A fair few deploys in there and some rake goodness too.
Advancing with Rails, day 3
Posted on April 25, 2008
Filed Under Rails, Ruby, Web | Leave a Comment
The penultimate day of David Black's 'Advancing with Rails' course covered some of the more technical aspects of Rails application development.
Security
We had quite an extensive review of how you can make your Rails application more secure. Rails now by default ships with the protect_from_forgery option enabled in the ApplicationController. This helps to protect your application from cross-site forgery.
Any request (e.g. form input) to your application that comes without the forgery protection token fails with a InvalidAuthenticityToken error. The token is, by default, submitted as a hidden field in your form.
attr_accessible and attr_protected
One thing I haven't made use of in the past but I really like the look of are the attr_accessible and attr_protected macros.
Using these macros it is possible to whitelist and perhaps more importantly blacklist those attributes that can and cannot be updated. If you had for example a User model with attributes name, hashed_password and nickname you could have the following in your model:
attr_accessible :name, :nickname
attr_protected :hashed_password
This statements mean that whilst it is possible to update the attr_accessible parameters through form input, the attr_protected attributes can only by updated through explicit modification (and not via form/url input).
Preventing SQL injection
This has been covered lots before but I still think it's worth reiterating. When specifying conditions on ActiveRecord functions the conditions should be specified as an array rather than using parameters directly in the query.
An example of a vulnerable query would be something like:
User.find(:all, :conditions => "name = #{params[:name]}")
There are a couple of things wrong here. Firstly, the find method is taking conditions from the params and putting them directly into the query SQL. If someone decided to post a query with some SQL e.g.
DROP TABLE users;
You might find you've had your users tables hosed.
The second problem with this is that queries like this really belong in the model layer of your application. So, a better version of this (potentially) dangerous code would be:
class User < ActiveRecord::Base
def self.find_by_name(name)
find(:all, :conditions => ["name = ?", name])
end
end
Then in your controller you call the function like this:
arfons = User.find_by_name("arfon")
The reason that this method of passing parameters to the query is safer is that Rails sanitises the parameters coming in thus protecting the database from a rogue query.
There was plenty more good stuff on day 3 including routes, URL recognition and REST but as it seems to be taking me an age to write up even the smallest part of the course I'm going to call it quits here…
Advancing with Rails, day 2
Posted on April 14, 2008
Filed Under Rails, Ruby, Web | Leave a Comment
I had hoped to post a daily updates on the rest of the 'Advancing with Rails course the week before last, but alas, life was a little too busy so here's what I particularly enjoyed on day 2.
Rails is all about the request cycle
Your application is basically just sitting there waiting for a request. When you send one, it responds then returns to its resting state. To be honest I'd never really given this much thought but it makes sense.
Your controller is your application
The controller is the thing that directs all of the actions, handing things off to other controllers / querying the model. Controllers have access to the whole application domain, can dip in an out of models as they please.
Redirect vs render
This is something that I'd never fully realised. When you
redirect_to => "action"
in your controller, you're actually starting a new request cycle. Crucially this means that all instance variables are reset. I've often found myself doing something like this in a controller:
def update
if something
success
else
redirect_to :action => "edit", :id => @item
end
end
If we were updating an item with a form and there had been an error caught by and ActiveRecord validation, the redirect would stop the error from showing up as the @item instance variable is reset when calling the redirect_to.
An alternative to this is the render method. Instead you can do this:
...
else
render :action => "edit"
end
end
This means that the instance variables are kept the same (i.e. not reset) and so errors would show up properly.
This is one of those things where experience had taught me to use a render rather than a redirect, but again, it was great to have it spelled out and explained fully.
Custom validations
It's possible to define a custom protected method called validate inside your models. Using this method you can add an error message on a particular field. In the case below, returning the error "Looser" if the name field equals "matt".
protected
def validate
errors.add(:name, "Looser") if name = "matt"
end
Another possibility is to have an 'inline' validation as follows:
validates_format_of :name, :with => some regex here, :message => "I don't think much of that name"
This is a good way of checking the format of a field, for example an email address.
Interestingly, every ActiveRecord object has an errors structure. If object.errors is empty then the object is valid (and will save).
After this we went into some hardcore Ruby hacking, but my eyes are too tired for all that now so more later…
Advancing with Rails, day 1
Posted on March 31, 2008
Filed Under Rails, Ruby, Web | Leave a Comment
Just finished my first day 'Advancing with Rails' courtesy of David A. Black. I'm happy to say that it's one of the most enlightening programming experiences I've had for quite some time.
It's rare that you get an opportunity to pick the brains of a real expert like David and with 3 more days of Ruby/Rails I'm sure there's plenty more good stuff to come.
Topics covered today included overriding ActiveRecord defaults (good for working with legacy databases, of which we have no shortage of here!), how to use initializers properly and why you might like to slim down your environment.rb. Composite primary keys (*blergh*), why class variables are tricky and best avoided, singleton methods and more!
Top two things for the day:
set_inheritance_column :fakecolumn
This is really useful when you have a 'type' column in your table and don't want Rails to think that you are working with single table inheritance. This is something that has caused me problems more than once.
Object.build(params[:associated])
By this I mean, say you had an auction model and
Auction has_many :items.
Should you want to create an auction and some associated items at the same time you might be tempted to do something like this in the controller:
@auction = Auction.new(params[:auction])
@item = Item.new(params[:item])
@auction.items << @item
This won't work because the @auction object hasn't been saved yet, doesn't have an ID and therefore doing:
@auction.items < @item
will fail as the auction_id column in @item won't be set.One way around this would be to put in the following before we create the new item:
@auction.save
This would work as @auction is now an ActiveRecord object. However, this has always seemed really scrappy. Today I learned that there is a much nicer way!
@auction = Auction.new(params[:auction])
@auction.build_item(params[:item])
@auction.save
In these three lines we've created the new Auction object and added an associated auction item by 'building' it. Nice eh?
Recently
- Slicehost
- History Meme
- Advancing with Rails, day 3
- Advancing with Rails, day 2
- Advancing with Rails, day 1
