Upgrading applications is good sport and all, but everyone knows that greenfielding is where the real fun is. At least, I love greenfielding stuff a lot more than dealing with old ghetto cruft that has 1,900 test failures (and 300 errors), 20,000 line controllers, and code that I’m pretty sure is actually a demon-brand of PHP.

Building a totally new app in Rails 3 is relatively simple (especially if you’ve done it in previous Rails versions), but there a few changes that can trip you up. In the interest of not missing a step someone may need, this post is a simple walkthrough of building a new app with Rails 3. I would have simply posted about the Rails 3 version of the Getting Started guide, but it’s actually a bit out of date now. I’ve committed each step in its own commit on Github so you can step through it (the repository is here: http://github.com/jm/rails3_blog)

An aside: Installing the Rails 3 beta

Installing the Rails 3 beta can be sort of tricky since there are dependencies, it’s a prerelease gem, and RubyGems basically poops the bed when those two scenarios collide. Hopefully that’ll be fixed soon, but the mean time, install Rails’ dependencies like so:

gem install rails3b gem install arel --pre # or if that gives you hassle... gem install i18n tzinfo builder memcache-client rack \ rack-test rack-mount erubis mail text-format thor bundler

Once all those lovely gems are installed (add --no-ri and --no-rdoc if you want to skip those/speed up your install), then install the prerelease version of Rails:

gem install rails --pre

Now you’re ready to roll on with the Rails beta!

Using the new generator

The application generator is basically the same with two key differences:

The parameter that was formerly the app name is now the app path. You can still give it a “name,” and it will create the folder like normal. But you can also give it a full path (e.g., ~code/my_application rather than just my_application ) and it will create the application there.

rather than just ) and it will create the application there. All parameters for the generator must go after the app path. So, previously one could do rails -d mysql test_app , but now that has to be rails test_app -d mysql . This change is largely due to the major refactoring of the Rails generators, so even though it’s somewhat of a temporary annoyance, it’s definitely worth it for the flexibility and power that the new generators bring (more on that soon).

So, let’s generate a blog application (really original, I know, right?):

rails rails3_blog -d mysql

If you get an error like “no value provided for required arguments ‘app_path’”, then you’ve gotten your parameters out of order. If you’d like to use another database driver, you can provide postgresql or sqlite (or nothing, since sqlite is the default). You’ll see a lot of text scroll by, and now we have a nice, fresh Rails 3 application to play with [4b6b763ac9378c6cde95b0815d2a4c2619a0e403].

Let’s crank up the server (note that it’s different now!)…

rails server

Rails went the “Merb way” and has consolidated its many script/* commands into the rails binscript. So things like generate , server , plugin , etc. are now rails generate and so on. Once the server’s booted, navigate over to http://localhost:3000 and you should see a familiar friend:

Click on “About your application’s environment” to see more information about the app you’ve generated.

Configuring an app

Now comes the task of configuration. Again, not a whole ton of changes from previous versions, but navigating them can trip up the novice and journey(wo)man alike. First, setup all your database settings in database.yml ; it’s just like previous versions of Rails, so no surprises there (and plenty of information abounds if you’re new to it).

Next, pop open config/application.rb . This is where much of the configuration information that once lived in config/environment.rb now lives. The portion you probably want to pay attention to most when making a new application is the block that defines your options for ORM, template engine, etc. Here’s the default:

config.generators do |g| g.orm :active_record g.template_engine :erb g.test_framework :test_unit, :fixture => true end

I’m going to stick with the defaults, but you could substitute in something like :datamapper or :sequel for :active_record , :haml for :erb , or :rspec for :test_unit (once they get it working with Rails 3). Doing so will set the generators for models, views, etc. to use your tool of choice (remember that whole technology agnosticism thing?); I don’t know if all these generators are available yet, but there are some available here.

The config/application.rb file also houses some configuration for other things.

If you need to configure internationalization, it’s been moved to application.rb . Rails 3 comes equipped with a really powerful i18n toolkit; if you haven’t seen it, you can learn a little more about it here. The defaults that Rails sets up will work for most people (default locale is en and all translations in the default directory are automatically imported), so you may not need to touch anything, but if you need to customize, this is the place to do it.

. Rails 3 comes equipped with a really powerful i18n toolkit; if you haven’t seen it, you can learn a little more about it here. The defaults that Rails sets up will work for most people (default locale is and all translations in the default directory are automatically imported), so you may not need to touch anything, but if you need to customize, this is the place to do it. You may want to set a default timezone. I usually stick with UTC since it’s easy to convert on a per-user basis to their desired timezone, but you might want to set it your timezone or the server’s timezone.

Your favorite old haunts from config/environment.rb such as config.plugins , config.load_paths , etc. are still there (even though config.gems is not).

Other configuration bits like custom inflections, mime types, and so on have been moved out into their own initializers that you can find under config/initializers . [b613cef6f92ff7d3304da84dba530196ba51371d]

The last big piece of configuration you’ll need to add is a Gemfile for bundler (get more information on Gemfiles and bundler here and here). We already have a basic Gemfile that has the following:

# Edit this Gemfile to bundle your application's dependencies. source 'http://gemcutter.org' gem "rails", "3.0.0.beta" ## Bundle edge rails: # gem "rails", :git => "git://github.com/rails/rails.git" gem "mysql" ## Bundle the gems you use: # gem "bj" # gem "hpricot", "0.6" # gem "sqlite3-ruby", :require => "sqlite3" # gem "aws-s3", :require => "aws/s3" ## Bundle gems used only in certain environments: # gem "rspec", :group => :test # group :test do # gem "webrat" # end

Notice that it has added mysql as a dependency since that’s what we set as the database (or whatever driver you selected, for example, pg or sqlite ). Since I want to write blog entries in Markdown, I’m going to add rdiscount as a dependency. To do so, I simply have to add this:

gem "rdiscount"

As I’ve said before, bundler is much more powerful than config.gem , and one of the great features it adds is the concept of a gem “group.” For example, let’s say I want to use mocha , but only when testing (obviously). You would add this to your Gemfile :

group :test do gem "mocha" end

Now this gem will only be added in when testing. This will also be useful for production only gems related to caching and what not. [598652fa49634eaa9d23ab8df652faf73dfd07f4]

Next, run bundle pack if you want to vendor everything or bundle install to install the gems to system gems. After you’ve combed through this stuff and set whatever you need, you’re done configuring your application. Now on to actually building something.

Building it out

So, we’re going to build a very simple blog (and expand it later). First, let’s generate a scaffold for posts, since that’ll generate a lot of boilerplate code that we’ll go back and tweak:

rails generate scaffold post title:string body:text invoke active_record create db/migrate/20100202054755_create_posts.rb create app/models/post.rb invoke test_unit create test/unit/post_test.rb create test/fixtures/posts.yml route resources :posts invoke scaffold_controller create app/controllers/posts_controller.rb invoke erb create app/views/posts create app/views/posts/index.html.erb create app/views/posts/edit.html.erb create app/views/posts/show.html.erb create app/views/posts/new.html.erb create app/views/posts/_form.html.erb create app/views/layouts/posts.html.erb invoke test_unit create test/functional/posts_controller_test.rb invoke helper create app/helpers/posts_helper.rb invoke test_unit create test/unit/helpers/posts_helper_test.rb invoke stylesheets create public/stylesheets/scaffold.css

Next, run rake db:migrate to create the database table for Post . Now if you go to http://localhost:3000/posts , you should see the standard scaffold interface. [8f27fe53282de70343afadaedd583ecc279d535d]

Let’s a take a look at the controller code; you’ll see a lot of actions that look sort of like this:

def show @post = Post.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @post } end end

That’s some clean code, but in Rails 3, we can compress down even further with the Responder . This class wraps very common rendering logic up into some really clean helpers. To use it, you’ll need to add what formats your actions respond with to the class:

class PostsController < ApplicationController respond_to :html, :xml . . . end

So your show action goes from the above to this:

def show @post = Post.find(params[:id]) respond_with(@post) end

Now the action will automatically look at the state of the object, the format requested, and respond accordingly. So, for example, if you successfully create an object in create , it will redirect to show ; if it fails, it will render new (this is assuming, of course, you’re requesting HTML). Of course, if you need custom logic, you’ll want to do something else, but these helpers make already clean, RESTful code even easier and cleaner. Make sure to rake to make sure you refactored it right! [53846f92393e10146fbf2d9b43b530a244d0137e]

Next, open up config/routes.rb . It should look something like this (with oodles of extra commented out routes):

Rails3Blog::Application.routes.draw do |map| resources :posts end

To set PostController 's index action to the root, we need to do two things. First, remove public/index.html otherwise it’ll always overtake any root route you set. Next, add a root route to config/routes.rb like this:

Rails3Blog::Application.routes.draw do |map| resources :posts root :to => "posts#index" end

Now going to http://localhost:3000 should show the posts index page. [120c377c8ec1c138d600f9b9bc39bedf1d43afd4] OK, so now that most of the functionality is in place, let’s make it look presentable; here’s my version of the index template:

<% @posts.each do |post| %> <h2><%= link_to post.title, post %></h2> <p>posted at <%= post.created_at.strftime('%D') %></p> <p><%= post.body %></p> <% end %> <%= link_to 'New post', new_post_path %>

You can see what other design edits I made in this commit [03b2c39d65331f7dfeb4ada89cf65604f7130e2d].

Now we need to add the Markdown functionality to the Post model. First, let’s generate a migration [2cbb0b04411ac1712a4f5039ed93bdad0cb6e76e]:

rails generate migration AddRenderedBodyToPosts rendered_body:text

Migrate your database, and now we’re ready to move on to testing. Write a simple test to make sure it renders the body after a save [af83a5a2e85a1679896e989f6828d1f5ee4aa7d3]:

require 'test_helper' class PostTest < ActiveSupport::TestCase test "renders Markdown after save" do post = Post.create(:title => "This post rocks.", :body => "Now *this* is an awesome post.") assert_equal "<p>Now <em>this</em> is an awesome post.</p>", post.rendered_body.chomp end end

If you rake now, that test should fail. So, let’s make it pass:

class Post < ActiveRecord::Base before_save :render_body def render_body self.rendered_body = RDiscount.new(self.body).to_html end end

You should be all green [4730cd4e8601c74a05b9763d307b462f76e44b26]! Now we’ll need to go back and change the instances of body to rendered_body on the index and show views.

That’s pretty standard Rails stuff, so let’s do something Rails 3-specific now. First, let’s add some validations; we’ll want to make sure that every post has a title and a body.

test "requires title" do post = Post.create(:body => "Now *this* is an awesome post.") assert !post.valid? assert post.errors[:title] end test "requires body" do post = Post.create(:title => "This post rocks.") assert !post.valid? assert post.errors[:body] end

Note the new API for Active Record errors (i.e., [] rather then on ) [930e8868b0e4d8904d6f5090f6b445b0c428f71f]. Now, of course, we have to make them pass…

class Post < ActiveRecord::Base before_save :render_body validates :title, :presence => true validates :body, :presence => true def render_body self.rendered_body = RDiscount.new(self.body).to_html end end

As you probably noticed, the API for Active Record validations I’ve used here is different (the validations shown are equivalent to a validates_presence_of validation, which are still around) [178bb06839bb44978f42c922c9348bfe783da8b1]. You can read a little more about the new style of validations here. So, now if you try to create a post without a title or body, it’ll reject it.

More later…

I realize this introduction is extremely simple, but I’ll expand on it very soon (including authentication, commenting, post drafts, an API, spam protection, feeds, caching, etc. with a separate entry after it on deployment). I’ll get to that sort of stuff very soon, but my next post is going to be a walkthrough of upgrading an app step by step (very similar to this entry). Look for it in a few days!

permalink