An aggregation of all the Rock Solid Knowledge Blogs
I'm assuming that most people reading this are .Net folk and that you will have at least a passing familiarity with ASP.Net, so occasionally I'll draw comparisons with Microsoft's framework. ASP.Net has had, since 2.0, the concept of Master pages. These are pages that provode the overall structure of parts of a web site. ASP.Net lets a page author design a template that contains content placeholders, this template is called a 'master page', individual pages can then specify that they want to use a specific master page and also specify which content replaces which placeholder within the page. Internally this turns out to be a fairly convoluted mechanism as the master page and the content page have to be woven together so that the right events get delivered to the right thing at the right time.
Rails, as you would expect, has a similar mechanism which known as 'layouts'.
In a Rails app, content is defined in a template. If you use the default generators of Rails 2.0 these templates are in the form of .erb files. A .erb file is essentially an HTML page with "turd-lets" of code embedded into it between <% %> and <%= %> symbols. This is just like other templating technologies such as ASP, ASP.Net, JSP or PHP
Templates are part of the view (obviously) and a typical template renders content for an action. For example in the rblog application there is a BlogsController class this has an index action with an associated index template. Of course none of this is mandatory, this is though the default behaviour if you use the scaffolding. The templates live in app/views and this index template lives in app/views/blogs/index.html.erb
The template looks something like this:
<h1>Latest Output</h1>
<div id='blog-entries-main-body'>
<div id='blog-entries'>
<% for blog_entry in @blog_entries %>
<div class='blog-entry-surround'>
<span class="blog-title"><%=h blog_entry.title %></span>
<div><%=h blog_entry.entry %></div>
<span class="blog-author"><%=h blog_entry.author_id %></span>
</div>
<% end %>
</div>
</div>
The template is a mixture of HTML and ruby. This Ruby code iterates over a collection of blog_entries (stored in @blog_entries) and for each one formats some output.
The action that causes this particular view to be rendered looks like:
def index
@blog_entries = BlogEntry.find(:all, :order => 'updated_at DESC', :limit => 10)
@blogs = Blog.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @blogs }
end
end
The first thing to note is that there are two member variables initialized, @blogs and @blog_entries. These are initialized in the controller and are also available in the view, that's where the view gets its @blog_entries reference from.
The other piece of interest is the respond_to section. This says that if the format is html use the default rendering (the '#' is a comment, so the 'index.html.erb' on that line is there as an aide memoire), and if the format is XML then use the XML renderer.
This means that when a request comes into /blogs then the index action of the blogs controller is executed, the @blogs and @blog_entries objects are created, control passes to the view and the output is rendered. However the output looks like this...
There is some extra stuff in here, for example there is styling and also things like a Register and Login button. This extra HTML comes from the layouts.
The layouts live in the app/layouts directory and by default there is one layout per controller, this is generated as part of the scaffolding. This means that if nothing explicit is done a default layout will be used, however there are various other ways to specify the layout needed, as will be seen.
The layout used for the blogs page looks like this
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>RBlog: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'general' %>
</head>
<body>
<div class="header" id="header">
<div id="header-message">
Welcome to RBlog
</div>
<div id="flash">
<p><%= flash[:notice] %></p>
</div>
<div id="logon">
<%= link_to "Register", :action => "register", :controller => "authenticate" %>
<%= link_to "Login", :action => "login", :controller => "authenticate" %>
</div>
</div>
<div class="main" id="main">
<%= yield %>
</div>
<div class="sidebar" id="sidebar">
<div id="bloglist">
<div id="blogs-list-title">Blogs</div>
<% for blog in @blogs %>
<div class="blog-title"><%= link_to h(blog.title), blog %></div>
<% end %>
</div>
</div>
<div class="footer" id="footer">
</div>
</body>
</html>
The highlights are:
It's the last one that's most interesting here. It's the call to yield that says 'take the default rendered output from the view and display it at this point in the page'. One thing to note here is that the view 'code' has already been executed at this point, i.e. the view template is rendered, that output is saved, then the layout is executed and the output from the template inserted into the layout.
This layout is called 'blogslisting.html.erb' so is not the default layout for the blogs controller, this means that the code has to explicitly specify this layout to use. Like many things in Rails there is a great deal of flexibility in doing this.
A global or default layout can be specified in app/controllers/application.rb , this contains the base class that all controllers derive from. A 'layout' declaration can be added In the class definition.
class ApplicationController < ActionController::Base layout "general"
A layout can also be specified per controller
class BlogsController < ApplicationController layout "blogslisting"
And this can be further overwritten on a per action basis. So if a given controller wants different layouts for each action it can have code something like this:
def show
@blog = Blog.find(params[:id])
respond_to do |format|
format.html {render(:layout => "layouts/blog" )}
format.xml { render :xml => @blog }
end
end
Where the code in the format.html block says to render with the layout with the 'layouts/blogs' layout file.
This piece is already much longer than I though it would be so it's time to stop. There's more to be said about this, such as getting multiple content into the layout (multiple calls to yield), and sharing content with partial page templates. More on that soon.
One of the driving forces of Rails is to make things easier for developers. It does this partly by taking decisions out of developers hands. It's an 'opinionated' framework, and one of the opinions it has is on the pattern to use for database access. Its choice in this case is the 'active record' pattern.
Rails has an ActiveRecord module and the model classes all derive from
ActiveRecord::Basefor example
BlogEntry < ActiveRecord::Base
it is this module that provides the active record support for the framework.
Like much of the rest of Rails, ActiveRecord follows naming conventions. Here for example the BlogEntry class represents a row in the blog_entries table. How does this happen?
Looking back to the Learning Rails - Part 2 post you will see that this script was run
script/generate scaffold blog_entry ...
This script created two files, the file with the model class BlogEntry definition and a "migration". The migrations are "scripts" that help create and mange the database definitions, essentially they are DDL for Rails.
Migrations are used to both set up and tear down databases. The files contain class definitions that specify the steps to take when managing the database.
Migrations are timestamped so that it is easy to apply migrations in the correct order and to rollback those migrations in reverse order if needs be. The migrations live in the db/migrate directory. Currently there are 4 migrations in there
20080925064318_create_sessions.rb 20080925065056_create_blogs.rb 20080925064319_create_users.rb 20080925065210_create_blog_entries.rb
The first is a fairly standard Rails migration that creates the session tables (run rake db:sessions:create to create this), the others are specific to this application. Each migration has a date-time as part of the file name and it's this name that determines the order in which the migrations are run. The 20080925065210_create_blog_entries.rb looks like this
class CreateBlogEntries < ActiveRecord::Migration
def self.up
create_table :blog_entries do |t|
t.string :title, :null => false
t.text :entry, :null => false
t.integer :author_id, :null => false
t.datetime :entry_added_date
t.datetime :entry_last_edited
t.timestamps
end
end
def self.down
drop_table :blog_entries
end
end
So it's a class that derives from ActiveRecord::Migration and provides two class methods (static methods to C#/C++ folks), up and down (it's the "self" that indicates that these are class methods and not instance methods). You can run the migration from the command line by using the Rake command
rake db:migrate
This runs any migrations that have not yet been run. How does it know which migrations to run? Tthere is a database table that holds the information about the migrations that have been run.
$ mysql -u root mysql> use rblog_development mysql> show tables;
shows something like
+-----------------------------+ | Tables_in_rblog_development | +-----------------------------+ | blog_entries | | blogs | | schema_migrations | | sessions | | users | +-----------------------------+
and
mysql> select * from schema_migrations; +----------------+ | version | +----------------+ | 20080923152418 | | 20080923152427 | | 20080923152435 | | 20080925064318 | | 20080925064319 | | 20080925065056 | | 20080925065210 | +----------------+
on my machine as I type this. Notice that the last entry in the table matches the datetime portion of the name of the last migration file.
When a migration is run (assuming it has not yet been added to the database), then the self.up method is executed. This method creates or modifies database entries. In the case of the blog_entries migration it creates the table and adds the eight columns from these five entries.
(title, entry, author_id, entry_added_date, entry_last_edited and timestamps
mysql shows this
mysql> show create table blog_entries; +--------------+---------------------------------+ | Table | Create Table | +--------------+---------------------------------+ | blog_entries | CREATE TABLE `blog_entries` ( `id` int(11) NOT NULL auto_increment, `title` varchar(255) NOT NULL, `entry` text NOT NULL, `author_id` int(11) NOT NULL, `entry_added_date` datetime default NULL, `entry_last_edited` datetime default NULL, `created_at` datetime default NULL, `updated_at` datetime default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +--------------+---------------------------------+
Notice that timestamps turns into two columns, and that an id column has been added as a primary key
A migration can also be rolled back. Running rake db:migrate rollback will rollback the last migration, or a specific version can be specified. For example rake db:migrate VERSION=20080925065056
Running the migrations this way runs the migrations in reverse order up to the specified migration, on the way the self.down mwthod of each migration is called. For the blog_entries migration that would drop the table. The down method should undo whatever the up method did!
One of the interesting (and frustrating) things about Rails is the way the migrations and the models work together. Running the script/generate scaffold blog_entry creates two files, the migration and the model. Looking in the model file there is ... nothing, just the class definition. The knowledge about the members of this class is in the migrations. This takes DRY (Do Not Repeat Yourself) to the limit but it can mean looking in several files (there maybe more than one migration per model) to find everything that the class uses. If the migrations get too "spread out", i.e. there are three or more migrations with modifications to one table then it is worth amalgamating those migrations into one file.
Now that we have a Rails app up and running, all be it a simple one, it's time to think about testing. When you generate an application you also get a test structure created for us. This structure lets us create unit, functional and integration tests. Each kind of test has a different scope and I'll start, as we should, with unit tests.
Looking in the test/unit directory there's a single ruby source file for each model created previously, each of these files looks like this
class BlogEntryTest < ActiveSupport::TestCase
# Replace this with your real tests.
def test_truth
assert true
end
end
Pretty straightforward, assert that true is true. (If this is your first glance at Ruby code the first line says that BlogEntryTest derives from TestCase and the 'def' statement defines a method).
Before running the test I create the test database
mysqladmin -u root create rblog_test
There are two ways (at least) to run this test, running
ruby -I test test/unit/blog_entry_test.rb
(-I test here includes the test directory in the search path) or
rake test:units
Running the first command line on my machine gives this:
Loaded suite test/unit/blog_entry_test Started E Finished in 0.033476 seconds. 1) Error: test_truth(BlogEntryTest): ActiveRecord::StatementInvalid: Mysql::Error: Table 'rblog_test.users' doesn't exist: DELETE FROM `users`
This shows us that the database tables don't exist. Running
rake db:test:prepare
fixes this and re-running the test now succeeds.
Started . Finished in 0.095619 seconds.
It's also possible to run
rake test:units
This will run all the unit tests
Started ... Finished in 0.056533 seconds. 3 tests, 3 assertions, 0 failures, 0 errors
Now that there's some confidence that the testing framework is in place it's time to start thinking about real tests.
The user class represents a user of the system, either a user with a blog or a user posting comments. This user must have a username, email and password. The user class looks like this
class User < ActiveRecord::Base validates_presence_of :name validates_presence_of :email validates_uniqueness_of :email validates_confirmation_of :password validate :password_non_blank
This suggest some tests. Does the user have a name and email, is the emil unique and does the password have some data! The first test checks that the user is valid
class UserTest < ActiveSupport::TestCase
def test_empty_user_is_invalid
user = User.new
assert !user.valid?
assert !user.errors.empty?
assert user.errors.invalid?(:name)
assert user.errors.invalid?(:email)
assert_equal "Missing password", user.errors.on_base
end
The test creates a User then calls the valid? method (if you're new to Ruby the ? on the end of a method is part of the method name and indicates that the method returns a boolean, a ! on the end indicates that the method mutates data) . The test asserts that the user is not valid and then asserts that the appropriate errors have been added to the errors collection.
The code has other tests for the user, checking that the password and password_confirmation match and that the password is not blank. There is also a test that a User is valid if all the fields are set correctly, none of these are shown here but the code is available here not that there's much to see at the moment!
The final test for the moment checks that the User must have a unique email. The code looks like this:
def test_user_unique_email
user = User.new(:name => "Test Name",
:email => users(:kevin).email,
:password => "wibble",
:password_confirmation => "wibble")
assert !user.save
assert_equal "has already been taken", user.errors.on(:email)
assert_equal ActiveRecord::Errors.default_error_messages[:taken], user.errors.on(:email)
end
The thing of interest in this code is the line
:email => users(:kevin).email,
This loads a fixture named :kevin. Fixtures are test data defined in a yml file (YAML Ain't a Markup Language) file. Fixtures have names and cen be loaded by name in the test code. The fixture looks like this:
kevin: email: kevin@test.com hashed_password: hash name: Kevin
The fixture data is loaded into the database, then the line 'users(:kevin).email' loads the fixture and gets its email value. This means that the test tries to save a user with the same email address as one that already exists, and that should fail.
I wanted to make this a series about Rails and about Ruby. To that end I'm going to write a series of entries on building an MVC application. As I said in the previous post I am a Ruby and Rails neophyte, so I'll be learning as I go along, regard this as a developer's journal. The aim being that you can learn from the mistakes that I make. If this really gets going I also hope to do some screencasts along the way.
What am I going to write - a blog of course (is there any other sort of web app out there today :) ). I chose blogging software because
I'm going to rely heavily on the 'Agile Development With Rails' book, and hopefully any feedback I get. I'm learning Ruby at the same time as Rails and Ruby is a very idiomatic language, I know I'll get some of the idioms wrong, so again feedback is welcome. Oh and initially I'm doing this on MacBook using TextMate as the editor. At some point I'm going to play with NetBeans and Eclipse as tools and so try out JRuby, not that I like a challenge of learning 17 new things at once!
So the beginning of a Rails app is the code generator, to create the application I fire up a terminal make sure I'm in the right directory and call
rails rblog
This gives the well known directory structure of
app config db doc lib log public script test tmp vendor
Most of the time I'll be in the app directory (that's where the models, controllers and views are), but I'll also use stuff from the db directory where the 'migrations' are stored, in the public directory where public the web files are and in config, where various setup files live.
Once the application has been created I can fire up another terminal (I usually have three open, one for my commands, one for the server and another to see the log file), change the the project directory and run the server with the command 'script/server'
This starts the server on port 3000, the server I'm using here is Mongrel, you can also start WEBrick. There's plenty of discussion on these servers out on the web so I won't go into the differences here.
Once the server is running you can point your browser at http://localhost:3000 and you should see something like:

I'm going to use MySql for the database and this needs to be configured. To do this I've edited config/database.yml to look like this:
development: adapter: mysql encoding: utf8 database: rblog_development username: root password: socket: /tmp/mysql.sock
Adding similar entries for test and production databases. Once that's done I created the development database
mysqladmin -u root create rblog_development
Now that all the necessary structure is in place I can create the first controllers and models. What do I know about the blog? I know it's going to have users, users can have blogs and blogs will have entries and comments. There may be more things eventually, such as tags, categories, pingbacks etc, but for now that's enough. So not to get too far ahead of myself I decided to create scaffolding for users, blogs and blogentries.
For the users model I'm going to user a similar approach to that used in the Rails book, so the user will have an email address and password, the password will be stored as a hash will be salted. A user will have a name that can be displayed on comments or on a blog and users may also own blogs. For now I'm going to limit this to one blog per user, but in the future this may expand to multiple blogs.
Running
script/generate scaffold user email:string hashed_password:string name:string blog_id:integer
gives me what I want. Doing something similar for blogs and blogentries
script/generate scaffold blog title:string sub_title:string owner_id:integer admin:boolean script/generate scaffold blog_entry title:string entry:text author_id:integer entry_added:datetime entry_last_edited:datetime
creates those models and their corresponding controllers and migrations.
Notice that as in my previous post I'm using singular names for the model components, so user, blog and blog_entry.
Now that's done it's then onto setting out some of the UI and writing some unit testing code.
I've been looking at Ruby and Rails for a long time, when I say looking at here what I really mean is staring through the glass and wondering what the fuss was about. Now that I finally have a MacBook I decided to actually sit down and learn Rails and Ruby at the same time. This means that on my hour long commute to and from my current contract I'm writing web code, and much fun it is. The commute is split over two trains so each part is about 30 minutes which gives me a very fractured learning experience but I'm still getting something done.
I wanted to use the web app I'm working on (it's only a toy) as a learning tool. This means that a) I wanted to minimize the new concepts and b) not be led by the hand too much. Because of that I decided that I would initially not use REST based routing as I would need to understand more about REST and using the built in routing would hide the routing system from me. So taking my routes in hand I initially did things the 'hard' way (actually, it's not that hard)
I finally figured that I knew enough to then try the RESTian approach, so firing up my trusty console, and TextMate I tried adding a new controller and model to the application.
I ran a command, something like,
script/generate scaffold foo
then ran
rake db:migrate
pointed the browser at http://localhost:3000/foos and everything seemed good. I added a new foo, life was good. Then I tried to browse to http://localhost:3000/foo/1 and I get an error:
Unknown action No action responded to 1
After much Googling and running of
rake routes
I couldn't find an answer.
Eventually after much re-reading of the routing chapter in The Book something must have lodged in my head and I decided to kill the web server and restart it, and suddenly the routes started working. The moral is "you do sometimes need to re-start the rails web server"!
The second issue was even more stupid. After fix the above problem, and getting my head more around the REST idea I decided I needed a bunch of controllers, so I duly run
script/generate scaffold bars
restart the server and immediately get strange errors along the lines of
undefined method `edit_bars_result_path' for #<ActionView::Base:0x255a508>
eh!
Rails experts will be laughing right now, or thinking 'been there, done that.' Rails adopts naming conventions, in this case models and controllers are singular. RESTian routing is based around the ideas of things and collections of things, the things are singular and the collections are plural. I tried to generated things that were already plural (bars), and the RAILs pluralization had no idea what to do with it, so the naming broke (at least that's what I think happened :) )