Level: Introductory Edd Dumbill (edd@usefulinc.com), Principal, Useful Information Company
22 Jun 2006 Learn how to speed your development of DB2®-based Web applications using the Ruby on Rails Web framework. Ruby on Rails is an open source Web framework causing a lot of excitement
among Web developers. By supporting agile development techniques and a
philosophy of "convention over configuration," it has enabled many developers
to radically reduce the time and pain involved in creating Web applications.
Because Rails emerged from the open source world, until recently you had to
use MySQL or PostgreSQL to work with it. Now that IBM has released a DB2 adapter for
Rails, it's possible to write efficient Web applications on top of your
existing DB2 database investment.
This article highlights some of the things that makes Rails
exceptional, explains how to get going with Rails and DB2, and leads you through
your first Web application in Rails.
What's special about Ruby on Rails?
Ruby on Rails, or "Rails" for short, hasn't risen to fame in the Web
development world without reason. Rails was originally conceived out of
real-world requirements, having emerged through the refactoring of a large Web application that its author, David Heinemeier-Hansson, was writing. This origin means that Rails is optimized to achieve its goals, rather than being the
result of an abstract API architecture, with all the tendencies such things
have to sprawl.
One of the biggest time-savers in Rails is convention over
configuration. Simple things such as naming your data model class with the
same name as the corresponding database table means that you don't have to
write needless mapping code, as do techniques such as always using "id" as
the primary key name. Of course Rails provides get-outs and overrides, but the
idea is only to use these when necessary.
As a framework, Rails implements the model-view-controller (MVC)
architecture. The MVC design pattern separates the component parts of an
application:
- A model encapsulates data that the application manipulates, plus
domain-specific logic.
- A view is a rendering of the model into the user interface.
- A controller responds to events from the interface and causes actions to be performed on the model.
The MVC pattern allows rapid change and evolution of the user interface and
controller separate from the data model, making it eminently suitable for Web
application programming.
Rails also enthusiastically embraces test-driven development. This is a
core part of agile software development methodology, and enables confident
evolution of an application. Rails has support for three different types of
testing:
-
Unit testing: Operating on the model.
-
Functional testing: Operating on individual controllers and their views.
-
Integration testing: Enabling application-wide testing.
Though many people accept that test-driven development is a good idea, it is often
ignored because of the inconvenience of writing tests. Rails leaves you few
excuses, as it brings tests right into the heart of the application
environment.
Rails as a platform
Everything in Rails is based around the Ruby programming language. If you don't
know Ruby, don't worry. It won't be too far from other languages you've come
across, such as Python, Perl, or Java. Though a knowledge of Ruby is going to be
very useful as you continue to develop in Rails, you don't need to know much to get started.
In production, Rails interfaces well with Web servers such as Apache and
Lighttpd. In development, it ships with a Ruby Web server so you don't need to fiddle around before getting started.
Rails requires no special file formats or integrated development environments (IDEs), you can get started with it
simply with a command line prompt and a text editor. That said, there are
various IDEs now with Rails support such as RadRails, which is a Rails environment for Eclipse.
Install Rails and the DB2 adapter
You can run Rails anywhere that you can run the Ruby interpreter. For Windows,
you can download a standalone package from the Rails Web site rubyonrails.org. For Linux, the best way is
to use the Ruby "gem" package manager to install Rails. Install Ruby in the
usual way for your Linux system, then download RubyGems. Unpack it, then run with:
When the gem system is installed, you can install Rails over the Internet:
# gem install rails --include-dependencies |
While some Linux package managers do include Rails, not all of them have up-to-date installations at this point.
If you don't have DB2 installed on the machine you intend to use, then you can
take advantage of the IBM Starter Toolkit, which includes both Rails and a DB2
installation in one. This is available for Windows right now, and will shortly
be available for Linux.
The DB2 adapter is available from alphaWorks in the "DB2onRails_Vx.x_Source.zip" package.
To install it, follow these instructions. This article uses Linux path separators ('/') by convention, so on Windows you'll need to adjust accordingly.
- Download and unpack DB2onRails_Vx.x_Source.zip.
- Copy the adapter/ibm_db2_adapter.rb file to the
activerecord-1.14.2/lib/active_record/connection_adapters directory (you can find this inside the site_ruby/1.8 directory in your Ruby installation).
- Build the adapter binary extension (ibm_db2.dll for Windows, ibm_db2.so for Linux).
- On Windows, copy the ibm_db2.dll file to the
lib\ruby\site_ruby\1.8\i386-msvcrt directory in your Ruby installation.
- On Linux, copy the ibm_db2.so file to the /usr/lib/ruby/1.8/i486-linux (or
similar) directory.
- Amend the activerecord-1.14.2/lib/active_record.rb file (adjust
this path to the right place for your Rails installation), and add ibm_db2
to the end of the
RAILS_CONNECTION_ADAPTERS array. It should then read something like this:
RAILS_CONNECTION_ADAPTERS = %w( mysql postgresql sqlite firebird
sqlserver db2 oracle sybase openbase ibm_db2 ) |
Now you should be ready to get going with your first Rails application.
Create a database for your Rails application
For the purposes of this article, it is assumed you're creating a new application from scratch. This lets you proceed along Rails' "golden path" of convention over configuration. Legacy databases can be put on Rails using a combination of Rails configuration and sometimes database views, but that's outside of the scope of this article.
For every application, Rails requires by default the specification of three different databases:
- A development database, which you code against.
- A test database, used for testing. The test database is volatile.
- A production database, used when the application is deployed.
The example application you're going to write is to underpin a directory of
software resources. I run a Web page that lists open source bug tracking
software, which is currently just managed as a text page. I've decided it would
be better to have the directory in a database, in order to be able to do more
with the data in the future.
Use the DB2 Control Center to create three databases: SOFTD_D, SOFTD_T, and SOFTD_P
for the development, testing, and production databases respectively. Unless you have a good reason not to, select the UTF-8 codeset for the database. This sets you up for internationalization from the start. The Control Center issues three commands like these (the exact command varies depending on your locale):
CREATE DATABASE softd_d AUTOMATIC STORAGE YES ON '/home/db2inst1'
USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096;
CREATE DATABASE softd_t AUTOMATIC STORAGE YES ON '/home/db2inst1'
USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096;
CREATE DATABASE softd_p AUTOMATIC STORAGE YES ON '/home/db2inst1'
USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096;
|
Create the Rails application
Now you've got a database to work against, it's time to create the Rails application. Open up a command prompt in your work directory and create
the application:
This creates a number of directories and files in the softdir directory.
The first thing you need to do is tell Rails how to speak to our database.
Edit the config/database.yml file and set it up as shown below.
development:
adapter: ibm_db2
database: softd_d
username: db2inst1
schema: db2inst1
password: yourpassword
host: localhost
port: 50000
# Warning: The database defined as 'test' will be erased and
# re-generated from your development database when you run 'rake'.
# Do not set this db to the same as development or production.
test:
adapter: ibm_db2
database: softd_t
username: db2inst1
schema: db2inst1
password: yourpassword
host: localhost
port: 50000
production:
adapter: ibm_db2
database: softd_p
username: db2inst1
schema: db2inst1
password: yourpassword
host: localhost
port: 50000
|
You need to replace the host, port, username, and password according to
your DB2 installation, if they differ from the defaults given here. You must
also select a suitable schema for connection, here just the default of
a schema matching the connecting username is given.
All that remains now is to start the development instance of your Web application, to check that all is OK.
In your Rails app directory, run ./script/server.
You should see the following output as the built-in Web server starts:
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2006-06-10 05:12:56] INFO WEBrick 1.3.1
[2006-06-10 05:12:56] INFO ruby 1.8.4 (2005-12-24) [i486-linux]
[2006-06-10 05:12:56] INFO WEBrick::HTTPServer#start: pid=3311 port=3000
|
Direct your Web browser to http://localhost:3000/ (or the hostname of your development box, if you're not running a local desktop) and you should see the welcome message below.
Figure 1. Rails welcome message
Create your first model
Now that the database is up and running, you can start creating models. For your
bug tracking software list, the most import model for you is that describing
a software project. The table below shows a first attempt at the data you want
to store.
Table 1. Data to store
| Field | Type |
|---|
| Name | String | | Description | Text | | Homepage | String | | License | String | | Opensource | Boolean | | Notes | Text |
As you read that table you were probably composing the necessary SQL to create it in your mind's eye. However, the approach in Rails is to avoid writing SQL commands when at all possible. This encourages a certain degree of database independence, it certainly makes an application more readable, and plays an important part in a feature called "migrations."
Migrations recognize that a database structure evolves as an application does, and there needs to be an ordered way to roll forward and backwards in the same way that version control allows for software.
The best way to learn is by doing, so create the model for your projects table. From the command prompt, run the generate script to create a model.
$ ./script/generate model Project
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/project.rb
create test/unit/project_test.rb
create test/fixtures/projects.yml
create db/migrate
create db/migrate/001_create_projects.rb
|
Rails has added all the infrastructure required for your first model:
- A class definition in app/models/
- Test code in test/unit/
- Test data (fixtures) in test/fixtures/
- A migration to create the table in db/migrate/
To define the table, edit db/migrate/001_create_projects.rb as shown below.
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.column "name", :string, :null => false
t.column "description", :text, :null => false
t.column "homepage", :string
t.column "license", :string
t.column "opensource", :boolean, :null => false
t.column "notes", :text
t.column "updated_on", :timestamp
t.column "created_on", :timestamp
end
end
def self.down
drop_table :projects
end
end |
Now run the migration by invoking the following:
$ rake migrate
(in /disk2/home/edd/work/softdir)
== CreateProjects: migrating ==============================================
-- create_table(:projects)
-> 0.8660s
== CreateProjects: migrated (0.8660s) =====================================
|
Figure 2 shows the result of the
migration. Rails has created a SCHEMA_INFO table to keep track of the
migrations, and added the PROJECTS table. The updated_on and created_on timestamps have been added to keep a track of changes
in the database, you will see later on that Rails updates these for free. Rails
also gives you a primary key for free, the ID column. As you'll see later,
you can suppress this if you need.
Figure 2. The PROJECTS table, viewed from the DB2 Control Center
You may also notice the default naming conventions in Rails. People tend
either to love or hate them, but it's a lot easier to love them. In general,
Rails aims for a natural (English) language feel to its directives, and the
first place you meet this is in the pluralization connected with model names.
- Database table name: projects
- Model class name: Project
- Model source file: app/models/project.rb
- Test data fixture file: test/fixtures/projects.rb
Create the user interface
With the first model created, it's time to add a controller and view so
some basic manipulation of the application is possible. Again, Rails'
generator script comes in handy here, by providing a quick way to write
the necessary boilerplate code. Craft some code for the administration
of the projects list.
$ ./script/generate scaffold Project Admin
|
The scaffolding creates basic code to support create, update, delete (CRUD) operations on the model. Visit http://localhost:3000/admin to see the interface where you can add, edit, and remove records.
Figure 3. The editing interface
Figure 4. The record list
Figure 5. The record view
While functional, these templates are barely usable and are only intended to provide you with a starting point.
To begin with, edit app/views/admin/_form.rhtml to make the form more usable
by making the text boxes a workable size, and removing the controls for the
timestamps, as Rails updates these automatically for you.
<%= error_messages_for 'project' %>
<!--[form:project]-->
<p><label for="project_name">Name</label><br/>
<%= text_field 'project', 'name' %></p>
<p><label for="project_description">Description</label><br/>
<%= text_area 'project', 'description', :rows => 3, :cols => 60 %></p>
<p><label for="project_homepage">Homepage</label><br/>
<%= text_field 'project', 'homepage', :size => 60 %></p>
<p><label for="project_license">License</label><br/>
<%= text_field 'project', 'license', :size => 10 %></p>
<p><label for="project_opensource">Opensource</label><br/>
<%= check_box 'project', 'opensource' %></p>
<p><label for="project_notes">Notes</label><br/>
<%= text_area 'project', 'notes', :rows => 3, :cols => 60 %></p>
<!--[eoform:project]-->
|
The RHTML files use embedded Ruby mixed with HTML. The instructions
such as text_field are helpers provided by Rails that generate HTML forms
for processing by the controller.
The development server reacts instantly to source changes, so reload the editing interface and try it out.
You will notice that it's possible to enter blank data for things
you do not wish to be empty, such as the name of a project. To fix this, you
need to add just a little more into the model class. Take a look at
app/models/project.rb and add in these constraints, shown in bold below:
class Project < ActiveRecord::Base
validates_presence_of :name
validates_presence_of :description
end
|
Notice how little code is required for the data binding. This is because
Rails relies on naming conventions and database introspection until you tell it
otherwise.
Finally, you can test the effects of this validation by attempting to enter an
empty name. You should see the error shown in something similar to that below.
Figure 6. Rails validation error reported to the user
What does everything do?
- app/models/: Contains the models, which encapsulate application business logic.
- app/views/layouts/: Contains master templates for each controller.
- app/views/controllername/: Contains templates for controller actions.
- app/helpers/: Contains helpers, which you can write to provide more functionality to templates.
- components/: Used for bundles of application functionality you might want to reuse (an advanced feature).
- config/: Contains application configuration, plus per-environment configurability.
- db/: Contains a snapshot of the database schema and migrations.
- log/: Contains a log for each environment (your first port of call if things aren't going as expected).
- public/: Contains all static files, such as images, javascripts, and style sheets.
- script/: Contains Rails utility commands.
- test/: Contains test fixtures and code.
- vendor/: Contains add-in modules. If you 'freeze' Rails, the system Rails gems are copied in here so you always know exactly which version you are running.
How does a request reach the code?
The mapping of an incoming browser request to the code that actually does the work in Rails is handled by routes, as stored in the config/routes.rb file.
By default, this mapping is of the form /controller/action/id, such as
in URLs similar to /admin/edit/100 that you have seen while editing the
project list. Rails finds the required controller, then looks for any method it
has corresponding to the action name. Finally, it displays the template found
in apps/views/controller/action.rhtml.
The value of id and any additional CGI query parameters are all
passed into the params hash, available to the controller and the views.
Add another model
Almost all useful database applications require more than one model,
and Rails provides some very powerful facilities for dealing with
relationships between tables.
For your bug tracker list to be useful to users, you need a way of enumerating
which facilities each tracker provides, such as an email interface, version
control system integration, or a public Web interface. These facilities can be
tracked in another model.
$ ./script/generate model Facility |
Edit the migration db/migrate/002_create_facilities.rb and add in the
definition for a facility.
class CreateFacilities < ActiveRecord::Migration
def self.up
create_table :facilities do |t|
t.column :name, :string
end
end
def self.down
drop_table :facilities
end
end |
Migrate the database with rake migrate and you're set. You can quickly scaffold a basic editor:
$ rake migrate
$ ./script/generate scaffold Facility facility |
Point your browser at http://localhost:3000/facility/ and add a few entries,
such as shown below.
Figure 7. Example facilities
What remains now is to be able to assign facilities to projects, through the use of a join table. Because you don't need an associated model, you just need to generate a migration:
./script/generate migration AddFacilitiesProjectsLink
|
Edit it to create the join table, suppressing the auto-supplied id field:
class AddFacilitiesProjectLink > ActiveRecord::Migration
def self.up
create_table(:facilities_projects, :id => false) do |t|
t.column "facility_id", :integer, :null => false
t.column "project_id", :integer, :null => false
end
end
def self.down
drop_table :facilities_projects
end
end |
Lastly, you amend the models to indicate the relationships. In project.rb, add:
has_and_belongs_to_many :facilities |
In facility.rb, add:
has_and_belongs_to_many :projects |
Again, thanks to convention, no more definition of column and table names is required. If you run the command line access to your Rails application, you see each model has a corresponding new method:
$ ./script/console
Loading development environment.
>> Project.find(:first).facilities
=> []
>> Facility.find(:first).projects
|
Finally, you must create the editing and display interfaces for the
links between the tables.
Edit the app/views/admin/_form.rhtml template an add in a new user
interface element as shown below.
<p><label for="project[facility_ids][]">Facilities</label><br />
<%= select_tag('project[facility_ids][]',
options_from_collection_for_select(Facility.find(:all, :order => 'name'),
'id', 'name', @project.facilities.collect {|f| f.id}),
:multiple => true
)%></p>
|
Figure 8. Editing interface with facilities selector
As you can see, this creates a list choice for linking
facilities to projects, and populates it by default with the existing
links. Naming conventions again ensure that Rails is responsible for updating
the link table.
If you examine the development log in logs/development.log, you see the SQL Rails is executing in response to your actions.
Summary
As a result of following this article, you now hopefully have your first Rails application up and running against DB2. This article has only been able to touch on the aspects of Rails, but the benefits of its pragmatic approach to Web development to productivity ought to be clear.
To learn more, you can follow one of the extended tutorials available from the
Ruby on Rails Web site, or buy a Rails book. I heartily recommend "Agile Web
Development with Rails" (Pragmatic Programmers), found in the Resources section.
For more help with Rails integration with DB2, watch the movies on the
alphaWorks site (found in the Resources section) and participate in the DB2 Rails Starter Kit forum.
Download | Description | Name | Size | Download method |
|---|
| Example code developed | softdir.tar.gz | 48KB | HTTP |
|---|
Resources Learn
Get products and technologies
-
RadRails:Is an IDE for Rails based on Eclipse.
- IBM's alphaWorks site hosts the DB2 Rails Starter
Kit. Help is available from the related forums.
-
Build your next development project with
IBM
trial software, available for download directly from developerWorks.
Discuss
About the author  | |  | Edd Dumbill is chair of the XTech conference on Web and XML technologies, and the principal of the Useful Information Company. Together with Matt Biddulph, he is available for delivering Ruby on Rails training to development teams. Edd has a Weblog called Behind the Times. |
Rate this page
|