March 21st 2007

Build an app with Ruby on Rails resources

Resources have been introduced in Rails 1.2. Basically this allows your application to expose content in different formats. Normal users with browsers get a nice HTML page while applications get easy to use XML code. Besides that Rails implements HTTP requests as GET, POST, PUT and DELETE.

All well, but how can you put this to your advantage when developing a Ruby on Rails application?

This article shows you how you can use Rails Resources as building blocks for your application. Let’s say you need to develop a simple portal application with news items and events. The news should have focus on the frontpage, but events should also be accessable on the frontpage.

Before I do anything more, I’ll create the a new rails project and use an sqlite3 database for ease of use.

$ rails --database=sqlite3 portal

Creating the building blocks

To start with the news I generate a scaffold_resource named article. This will give me an articles controller and an article model. This is the first building block.

$ ./script/generate scaffold_resource article title:string body:text

Before you migrate your database, edit the migration in db/migrations/001_create_articles.rb:

class CreateArticles  false, :default => "", :limit => 100
      t.column :body, :text, :null => false, :default => ""

      t.column :created_at, :datetime
      t.column :updated_at, :datetime
    end
  end

  def self.down
    drop_table :articles
  end
end

Next we create the second block named ‘event’.

$ ./script/generate scaffold_resource event title:string happens_on:date description:text

and the migration is edited to look like this:

class CreateEvents  false, :limit => 100, :default => ""
      t.column :happens_on, :date, :null => false
      t.column :description, :text, :null => false, :default => ""

      t.column :created_at, :datetime
      t.column :updated_at, :datetime
    end
  end

  def self.down
    drop_table :events
  end
end

Migrate your database next:

$ rake db:migrate

You may now start your webserver and enjoy all the scaffold goodness. You can CRUD articles and events now! Everything is still in scaffold from, but it’s a good start.

Adding some routing magic

You’ll never display all news items on your frontpage. You probably want the ten latest items and the newest first. For this to integrate nicely with the article resource we’ll add a new route and a simple method to the articles controller.

In app/controllers/articles_controller.rb add the following method:

  def latest
    @articles = Article.find(:all, :limit => 10, :order => "created_at DESC")

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

and in config/routes.rb you should replace

map.resources :articles

with

map.resources :articles,
  :collection => {
    :latest => :get
  }

You may also want to create a file named app/views/articles/latest.rhtml. This may, for now, be a copy of app/views/articles/index.rhtml.

Now you can access http://localhost:3000/articles;latest to get the ten latest articles, newest first.

Let’s do the same for events, but in this case we want the five next events in our database.

app/controllers/events_controller.rb:

  def upcoming
    @events = Event.find(:all, :limit => 5, :order => "happens_on", :conditions => ['happens_on >= ?', Time.now])

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

config/routes.rb:

  map.resources :events,
    :collection => {
      :upcoming => :get
    }

Again, copy app/views/events/index.rhtml to app/views/events/upcoming.rhtml for now. http://localhost:3000/events;upcoming now shows the next five events that are going to happen.

Make things more sexy

Okay, now let’s spice up the latest.rhtml and upcoming.rhtml views. You may copy/paste the following:

app/views/articles/latest.rhtml:

Latest articles

app/views/articles/upcoming.rhtml:

Upcoming events

This will make those special collections look a bit nicer.

Putting it all together

Now you have your building blocks ready, start building! I prefer to create a special controller that handles special pages like the frontpage.

$ ./script/generate controller pagemill

Add a simple method to the controller to show a frontpage. All the magic will happen in the view, so you controller basically looks like this:

class PagemillController 


Now create a file app/views/pagemill/frontpage.rhtml

< %= render_component :controller => 'events', :action => 'upcoming' %>

Portal Frontpage

Some standard talk about this portal goes here.

< %= render_component :controller => ‘articles’, :action => ‘latest’ %>

Only two things to do, first remove the default public/index.html

$ rm pubic/index.html

and add a default route in config/routes.rb

map.connect '', :controller => "pagemill", :action => "frontpage"

Enjoy your hard work

You can now enjoy your hard work by surfing to http://localhost:3000.

What's next?

There’s still a lot to do:

  • Add some more style and colours (use the CSS, Luke)
  • Change the templates I specified here to suit your needs.
  • Include additional information for your articles and events.
  • Change the templates when viewing an article or event.
  • Add some basic navigation
  • Protect your site by adding users and permissions

Too lazy to copy/paste?

You may download this rails project. I’ve used Rails 1.2.2 on Mac OS X and SQlite3. Of course you can use other databases like MySQL if you like.