Ruby on Rails
We have written previously about the outsourcing of the web stack. In this post, we will add more color on why the outsourcing of the entire web platform makes sense. While developers have gravitated en masse to offerings like Heroku, there is still a wider lack of appreciation for why PaaS is a major trend.
In this post, we are going to set aside the wider question of the economics of running your application on a PaaS versus hosting and maintaining your own servers. Our aim is to describe what constitutes a PaaS and how it differs from IaaS (such as Amazon Web Services) and other SaaS offerings like Salesforce.com.
The Four Pillars of a PaaS
- No installation required. Whether your application is written in Ruby on Rails, Python, Java or any other language de jour there should be no need to install an execution environment when deploying your application to a PaaS. Your code should run on the platform’s built-in execution engine. While minor constraints are necessary, our view is that the successful PaaS providers will largely conform to the language specifications as they are in the wild. This ensures portability of your application between platforms and other hosted environments.
- Automated deployment. A single click or command line instruction is all that stands between the developer and a live application.
- Elimination of middle-ware configuration. Tweaking settings in Apache or Nginx, managing the memory on your MySql instance, and installing three flavors of monitoring software are now in the past.
- Automated provisioning of virtual machines. Application scaling should happen behind the scenes. At 3am. Without breaking a sweat.
There are a few other characteristics of the new breed of PaaS services which we would regard as optional components of a platform but which greatly enhance its utility. By integrating other components into the web stack and constraining these to a few, well-curated and proven bundles, a PaaS offering can both consolidate services into a single bill but, perhaps more importantly from a developer’s point of view, ensure inter-operability and maintain a best-of-breed library. Heroku has done a great job of facilitating easy deployment of application add-ons such as log file management, error tracking, and performance monitoring.
There is often confusion as to the difference between PaaS and SaaS: a PaaS offering is an outsourced application stack sold to developers. A SaaS offering is a business application typically sold to business users.
The difference between PaaS and IaaS is more subtle and over time the dividing line is likely to blur. Today, the PaaS platforms begin where the IaaS services leave off: IaaS effects the outsourcing of the hardware components of the web stack. PaaS platforms effect the outsourcing of the middleware components of the web stack. It is the abstraction of the repetitive middleware configuration that has caught the imagination of developers. PaaS saves time and expedites deployments.
It is a great time to be a web software developer. Over the last decade the components of web development which have little strategic advantage to a start up have gradually been eliminated and outsourced to such an extent that today the gap between writing code and deploying a new application is often bridged with a single click.
Whereas ten years ago deploying a new application required provisioning a new server, installing Linux, setting up MySQL, configuring Apache, and finally uploading the code, the process today has dramatically less friction. On Heroku, one powerful command line is now all that stands between a team of developers and a live application:
> git push heroku master
Let’s take a closer look at what is happening. The code residing in the repository is uploaded directly to, in this example, Heroku’s cloud platform. From that point onward, the long list of tasks involved in maintaining and fine-tuning a modern web stack are outsourced. The platform provider handles hard drive failures, exploding power supplies, denial-of-service attacks, router replacement, server OS upgrades, security patches, web server configuration … and everything in between.
The implications of this trend are bound to be far-reaching. As common infrastructure is outsourced to vendors such as Amazon, Rackspace, Google and Salesforce.com, the base of customers for hardware and stack software will become increasingly concentrated. As the platform vendors function both as curators and distributors of middle-ware for associated services such as application monitoring and error logging, new monetization opportunities will arise for those companies, such as New Relic, providing these tools.
Just as the arrival of open-source blogging platforms eliminated the intervening steps between writers and audiences, so the new breed of platforms has reduced the friction between developers and their customers.
Most importantly, though, the barriers for new private companies to compete have been permanently lowered. Today, $100 per month can buy you a billion dollar data center.
I used Ubuntu 10.04 so that I know I don’t need to upgrade for the next four years.
1. Follow Linode’s excellent ‘Getting Started‘ instructions.
2. Add a new user and add them to the sudoers file.
3. Use Josh’s ‘Railsready‘ script to install Ruby etc.
Rather than using RVM to create gemsets, I prefer to ‘Vendor Everything‘, so I didn’t use RVM to install Ruby.
4. Install Passenger (this will also install nginx)
In this way you can obtain the list of the ten oldest processes:
ps -elf | sort -r -k12 | head -n 10
To sort processes by memory usage use “Shift M” when running.
Use ‘c’ to show full path for command.
For other useful ‘top’ configurations.
When you’re debugging/analyzing MySQL queries in the Rails console, it helps to turn on ActiveRecord logging:
#Enable ActiveRecord logging def loud_logger(enable = true) logger = (enable == true ? Logger.new(STDOUT) : nil) ActiveRecord::Base.logger = logger ActiveRecord::Base.clear_active_connections! end
collect {|item|block} and map{|item|block} do the same thing – return an array of things returned by the block. This is different from returning specific items in the collection being iterated over.
Which leads to select.
select{|item|block} will return actual collection items being iterated over if, for each item, the block condition evaluates to true. Not the same as returning what the block, itself, may return. In the case of select, the block would always return an instance of class TrueClass or FalseClass. Typically, [true, false, ..., true] is not what you’re looking for in your resulting array.
Slightly modifying the core RDoc example:
a = ["a", "b", "c", "d"] #=> ["a", "b", "c", "d"]
a.map {|item|"a" == item} #=> [true, false, false, false]
a.select {|item|"a" == item} #=> ["a"]
If you’re trying to run the rake task required for installing Cucumber in Rails and keep getting the following error message:
rake aborted!
undefined method `select’ for class `ActiveRecord::ConnectionAdapters::MysqlAdapter’
Check to see whether you’re using the query_analyzer plugin. I had to uninstall it to get the rake task to complete using:
script/plugin remove query_analyzer
That solved the problem
Assuming you want to make sure that no two models have the same COMBINATION of values for a and b:
so having two models with:
a = 1, b = 2
a = 1, b = 3
would not be a conflict.
If that’s the case then the standard validation
class Widget < ActiveRecord::Base
validates_uniqueness_of :a, :b
end
wouldn’t work since it tries to prevent saving two models with the same value of a, OR with the same value of b.
And even if that’s not what you’re trying to do, and you’re ok with the example being a conflict, validates_uniqueness_of doesn’t guarantee uniqueness if two users try to save conflicting records simultaneously. The validation works by first trying to find a record with the value, and if it doesn’t find it inserting the ‘new’ record, and this can fail due to a concurrency hole.
To fill this hole requires leaning on the database server, and the way to do that in SQL is by having a unique index on the table which covers the column or columns you want to be unique. This assume you are using a database which supports it, e.g. MySql.
To create an index you can create a migration which includes a statement like
add_index :widgets, [:a, :b], :unique => true)
Assuming that the table name for the model is ‘widgets’
Now if you do this, you also need to be aware that if you try to save a record with a uniqueness conflict the save will raise an ActiveRecord::StatementInvalid exception, which you’ll need to rescue and do something like telling the user of the conflict so that he can rectify it.
After downloading the latest Ubuntu desktop appliance from VMware, the following steps are required to get a Rails environment up and running:
Create a new user and add all the required access
Get Ubuntu up to date
sudo apt-get update sudo apt-get dist-upgrade
Install compile packages
sudo apt-get install build-essential
Install Ruby, MySQL and the Open SSL library
sudo apt-get install ruby ri rdoc mysql-server libmysqlclient15-dev libopenssl-ruby ruby1.8-dev
Install Sun Java
sudo apt-get install sun-java6-jre sun-java6-plugin
Get the latest ruby gems from RubyForge
wget http://rubyforge.org/frs/download.php/57643/rubygems-1.3.5.tgz tar xvzf rubygems-1.3.5.tgz cd rubygems-1.3.5 sudo ruby setup.rb
Remove the .tgz file and erase the rubygems-1.3.5 directory too.
Create the following symbolic links
sudo ln -s /usr/bin/gem1.8 /usr/local/bin/gem sudo ln -s /usr/bin/ruby1.8 /usr/local/bin/ruby sudo ln -s /usr/bin/rdoc1.8 /usr/local/bin/rdoc sudo ln -s /usr/bin/ri1.8 /usr/local/bin/ri sudo ln -s /usr/bin/irb1.8 /usr/local/bin/irb
Install Rails
sudo gem install rails
Add Github for legacy gems
gem sources -a http://gems.github.com
Switch to Gemcutter for primary gem repository
sudo gem install gemcutter gem tumble
