Introduction to AWS for Ruby Developers

Articles & Tutorials>Introduction to AWS for Ruby Developers
Are you new to Amazon Web Services? This brief tutorial introduces you to Amazon Web Services from the eyes of a Ruby developer, walks through a simple example, and links to other helpful resources to get you started.

Details

Submitted By: Robert Dempsey
AWS Products Used: Amazon EC2, Amazon S3, Amazon SQS, Amazon SimpleDB
Language(s): Ruby
Created On: June 26, 2007 3:50 PM GMT
Last Updated: September 21, 2008 10:16 PM GMT

By Robert Dempsey of Atlantic Dominion Solutions, LLC

Abstract

With Amazon Web Services™ (AWS), developers are no longer limited by expensive-to-scale infrastructure, lack of funds to build a data center, or a smaller IT staff. To meet increasing client demands to store ever-growing data, mine vast amounts of information, and gather information from the Internet, developers turn to AWS. Ruby and Rails are the perfect combination to work with the services. Getting started with most of the AWS solutions requires little or no experience with Ruby, Rails, or AWS, making the services extremely simple to use and highly addictive. This article, which assumes a basic understanding of the Ruby programming language and the Ruby on Rails framework, shows you step-by-step how easy it is to use freely available tools to integrate AWS into your Rails application.

Introduction to Amazon Web Services

Amazon Web Services (AWS) provides developers with direct access to a powerful suite of web services that enhance and power their applications.

These services, which you can access by using Simple Object Access Protocol (SOAP) or representational state transfer (REST), can be used individually or in unison to equip developers with enterprise-class tools—without the management overhead. Rails developers are ready to go with Ruby gems (packaged Ruby applications or libraries) available for Amazon EC2, Amazon Associates Web Service, and Amazon S3 and with plugins, such as Paperclip, that have AWS capability baked right in.

REST or SOAP: Which Keeps Code Cleaner?

The two ways to work with web services by using Ruby and Rails are REST and SOAP. SOAP is "a protocol for exchanging XML-based messages over computer networks, normally using HTTP" (Wikipedia.com, SOAP). Action Web Service (the portion of Rails used to create and interact with SOAP and XML-RPC-based web services) will soon be removed from the core and implemented in a plugin. Action Web Service requires the creation of an application programming interface (API) definition and a controller, the use of dispatching modes, and more. A Ruby gem is available to help Rails developers use SOAP; however, because SOAP is being removed from the Rails core, REST is a better alternative.

Built into the core of Rails and featured heavily in Ruby on Rails 2, REST is a simple-to-implement architecture that uses HTTP and XML for communication. Whereas SOAP is a protocol, REST is a software architecture: a way of designing web applications. REST allows client applications to retrieve content from a site simply by knowing the appropriate URL to call. The XML that is returned contains and describes the content in a single response. With Ruby on Rails, you can code a REST-enabled application from the beginning, resulting in one code base that provides functionality and an API.

RESTful Development with Ruby on Rails

In Agile Web Development with Rails, author Dave Thomas states that in REST, "we use a simple set of verbs to operate on a rich set of nouns...the verbs correspond to HTTP methods (GET, PUT, POST, and DELETE)...the nouns are the resources in our application. We name those resources using URLs" (p. 407). In other words, to interact with a RESTful Rails application, the client simply calls URLs and sends and receives XML. URLs are automatically generated by a few lines of code in your config/routes.rb file. For example, suppose you have an inventory application that keeps track of products that you have stored in various warehouses. For simplicity, your database contains one table (authentication aside): products. Your routes.rb file contains the following:

ActionController::Routing::Routes.draw do |map|
	map.resources :products

	# Allow downloading Web Service WSDL as a file with an extension
	# instead of a file named 'wsdl'
	map.connect ':controller/service.wsdl', :action => 'wsdl'
	
 	# Install the default route as the lowest priority
 	map.connect ':controller/:action/:id.:format'
 	map.connect ':controller/:action/:id'
end

With these two lines (and a dash of code in your controllers), other applications have the ability to request and send product information to and from your database. Too easy, you say? Not in Rails. To prove how simple this process is, I'll show you how to create a small application that stores product information and takes advantage of Amazon S3 to store product images.

REST for a Bit

Now the moment you have been waiting for (or have skipped to): the code.

Note: Although I use a Mac for development, the commands that follow are the same regardless of your operating system. The code was developed by using Ruby 1.8.7 and Ruby on Rails 2.1.0.

You are going to create a little application that keeps track of products and their images. The application will take advantage of the Paperclip plugin from thoughtbot. This plugin can use the Amazon S3 service to store the images (and other types of files, if you like). I am focusing on Amazon S3 because it is one of the simplest of the AWS solutions to use, more applications now allow user-generated content that needs to be stored, purchasing storage becomes cost-prohibitive very quickly, and getting started with Ruby on Rails takes but a few lines of code.

Before delving into working with AWS, install the most recent version of Rails:

sudo gem install rails

Next, sign up for a free AWS account. After providing credit card information for the Amazon S3 service, you'll receive an Access Key ID. To connect to AWS with Rails, you will need to use a Ruby gem. Several Ruby gems interact with AWS, but you will use two written by RightScale. The two gems give you access to all AWS services. To install the gems, run the following command in your terminal:

sudo gem install right_aws right_http_connection

Next, create a new Rails application and tell it to use a MySQL database. Let's call the application aws_article:

Musashi:~/Documents/rails rdempsey$ rails aws_article --database mysql

That was easy! Next, you'll create your development and test databases, and configure your database.yml file to connect to them. Use the username and password appropriate for your database.

development:
  adapter: mysql
  encoding: utf8
  database: aws_article_development
  username: root
  password:
  socket: /tmp/mysql.sock

test:
  adapter: mysql
  encoding: utf8
  database: aws_article_test
  username: root
  password:
  socket: /tmp/mysql.sock

production:
  adapter: mysql
  encoding: utf8
  database: aws_article_production
  username: root
  password: 
  socket: /tmp/mysql.sock

Now it is time to download the Paperclip plugin. This plugin makes it easy to attach files or images to any model you create, and has excellent documentation. To install the plugin, run the following command in your Rails root directory :

svn export https://svn.thoughtbot.com/plugins/paperclip/trunk/ vendor/plugins/paperclip

To use Amazon S3, you need a config file. Create a file named s3.yml and save it in your config directory. In this file, add the Access Key ID and Secret Access Key that you received when you signed up for Amazon S3. Type your keys. (I am not giving you mine!)

Now that you are set up, you need to create your RESTful models and controllers. With Rails 2.1.0, when you run the "generate scaffold" command, the created controller will automatically be RESTful, and the required map.resource lines will be added to your routes.rb file. To create the scaffold model, controller, views, and a migration for your product, run the following:

script/generate scaffold Product name:string purchase_price:decimal sale_price:decimal photo_file_name:string photo_content_type:string photo_file_size:integer

By listing all the fields and data types that you are going to use, the scaffolded forms that are created will have all the fields we need. The migration will also have all your required fields. Open your migration file and add the limit, precision, and scale attributes where necessary so that your migration looks like the following:

	class CreateProducts < ActiveRecord::Migration
	  def self.up
	    create_table :products do |t|
	      t.string :name, :limit => 255
	      t.decimal :purchase_price, :precision => 10, :scale => 2
	      t.decimal :sale_price, :precision => 10, :scale => 2
	      t.string :photo_file_name
	      t.string :photo_content_type
	      t.integer :photo_file_size
				t.timestamps
	    end
	  end

	  def self.down
	    drop_table :products
	  end
	end

Before moving ahead, add :html => { :multipart => true } to our form tag and Image: <%= f.file_field :photo %> so that you can upload files. Add this code to both the new and edit forms. The new form will looks like the following:

	New product
	<% form_for(@product, :html => { :multipart => true }) do |f| %>
	  <%= f.error_messages %>
	    <%= f.label :name %>
<%= f.text_field :name %> <%= f.label :purchase_price %>
<%= f.text_field :purchase_price %> <%= f.label :sale_price %>
<%= f.text_field :sale_price %> Image: <%= f.file_field :photo %> <%= f.submit "Create" %> <% end %> <%= link_to 'Back', products_path %>

Next, open the config/routes.rb file and check to be sure that it includes the following:

map.resources :products

Note: map.resources. Those lines produce the URLs that will be used for your RESTful interface. What are the URLs, you ask? Good question. Here's the list for products:

Controller Action HTTP Method URL XML
index GET /products /products.xml
show GET /products/1 /products/1.xml
new GET /products/new  
edit GET /products/1;edit  
create POST /products /products.xml
update PUT /products/1 /products/1.xml
destroy DELETE /products/1 /products/1.xml

Open your controller and look for the following:

# GET /products
# GET /products.xml
def index
  @products = Product.find(:all)

  respond_to do |format|
    format.html # index.rhtml
    format.xml  { render :xml => @products.to_xml }
  end
end

Update your database by running a migration and ensuring that everything works correctly:

rake db:migrate

If you've seen any Rails code created before Rails 2.1, then you might recognize the @products = Product.find(:all) line in apps/controllers/product_controller.rb. Because Rails 2.1 has REST baked right in, you can now see the respond_to block in your controller.

# GET /products
# GET /products.xml
def index
	@products = Product.find(:all)

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @products }
  end
end

Here, you can see that for the index method, the index file (located at /products) will return both HTML and XML. You have just accomplished two tasks with one command: You generated the scaffold code and created the RESTful API. Good stuff. After you fire up Mongrel and test your controller actions, you'll turn your attention to configuring the application to use Amazon S3.

Time to go to the Product model and update it to work with the Paperclip plugin. Here's what your Product model should look like:

class Product < ActiveRecord::Base
  has_attached_file :photo,
                    :styles => { :medium => "300x300>",
                                 :thumb => "100x100>" },
                    :storage => :s3,
                    :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
                    :path => ":attachment/:id/:style.:extension",
                    :bucket => 'introtoruby_development'
end

Note: Change your bucket name to the bucket in which you want to store your images.

That's it: No additional configuration required. You are now ready to rock. Open up a terminal session, change to the root directory of your application, type script/server, and then go to http://localhost:3000/products.

Create a new product and upload the image. If you look in your development database, you'll see the record for the uploaded file - photo_file_name. The Paperclip plugin also provides type and size information. To confirm that the image was uploaded to Amazon S3, add the following code as a tag in the show form:

<%= image_tag @product.photo.url %>

When you pull up the show page, the view retrieves the image from Amazon S3 and displays it on the page. Quick and simple.

Only an App

What do you do when all you have is an application? Deploy it, of course! Depending on your level of comfort, you have several great options for deploying the application onto Amazon EC2:

Company Required skill level Deployment options
Morph Labs Beginner Use a Capistrano deploy file that they provide.
Heroku Beginner Create an app via their interface or import an existing application.
RightScale I know a bit RightScale provides the most control over your deployment with a full suite of tools. When the environment is set up, you can install and update your application with the click of a button.
PoolParty I know a bit They are working on Capistrano deployment, so for now, it's manual.
Elasticfox Firefox Extension for Amazon EC2 I know a bit The extension helps to create and manage instances. Deployment is done by using Capistrano.
Amazon Web Services Expert Command-line tools.

Time for an Upgrade

You can deliver true power to your applications by using a combination of AWS solutions. Is doing so difficult? Not with Ruby and Rails. The RightScale Ruby gem makes it ultra simple. One easy way to extend the application that you built is to use Amazon SimpleDB (rather than MySQL) as the database. Martin Rehfeld has written an excellent article that shows you how to do just that.

Conclusion

Today's web-based applications are required to provide more storage, more compute power, and a greater level of reliability than ever before. With a pay-as-you-go model, AWS, combined with freely available Ruby gems and Rails plugins, provides enterprise-class capability to Ruby on Rails applications. Using the power of Ruby on Rails and RESTful web services, developers can get up and going in hours instead of days. Try it!

Learning More About AWS

This article highlights a few aspects of working with AWS. Visit the following web sites for resources on Ruby and Rails and to learn more.

AWS Resources

  • Learn more about each web service on the AWS web site.
  • The Developer Connection web site for AWS developers includes forums on AWS, a solutions catalog with examples of what your peers have built, and more.
  • Part of the Developer Connection web site, the Resource Center has links to tutorials, code samples, technical documentation, and other resources for building your application on AWS.

Resources for Ruby and Rails Developers

Ruby and AWS Real-World Examples

The following web sites use Amazon Web Services and Ruby on Rails:

References

About the Author

After 8 years as an MCSE and project manager, Robert Dempsey jumped from IT management and PHP/Visual Basic.NET development to Ruby on Rails. He is the CEO and Founder of Atlantic Dominion Solutions, a web development firm specializing in Ruby on Rails, and the founder of Rails For All, a not-for-profit organization dedicated to educating business and developers about Ruby on Rails. In addition, Robert presents on a regular basis at the Orlando Ruby Users Group, and talks to Java user groups on topics including JRuby and Ruby on Rails.

Comments

Many Thanks
An awesome learning experience for me! As someone fairly new to Ruby and completely new to S3, a couple of points that might make this example easier for others in my boat: 1. The format of s3.yml that worked for me was: access_key_id: 'ACCESS_KEY' secret_access_key: 'WOULDNT_YOU_LIKE_TO_KNOW' 2. The scoping of the added first added photo to S3 (and subsequent ones of course follow the numerical pattern) is easy to overlook, and is something to the tune of: http://my_bucket.s3.amazonaws.com/photos/1/original.JPG Pretty darned RESTful! Thanks for this example!!
timbreeden on October 1, 2008 5:53 PM GMT
We are temporarily not accepting new comments.
©2014, Amazon Web Services, Inc. or its affiliates. All rights reserved.