Saturday, December 27, 2008

Merb blog tutorial

I started using merb a few days ago. After searching through the net, I couldn't find any working blog example for merb (that also uses datamapper) that I'm using. Yes, I know that the new documentation is underway, but I'd rather get this out quickly. (And, yes, I know that merb 2 = rails 3.)

This tutorial just tries to be an shorter updated version of this great tutorial "merb + datamapper + noob: quick start" (from a slightly different viewpoint). It also assumes that you have some knowledge of rails.

First you have to install merb. The easiest way is to just
$ sudo gem install merb

Because we'll use datamapper and sqlite3:
$ sudo gem install datamapper merb_datamapper do_sqlite3

Start by generating merb application:
$ merb-gen app blog

Using this merb-gen app command generates an empty merb application that uses datamapper.

In blog/, you'll find a familiar directory structure. As in rails, configuration files are in config/. The ones that you want to look at are dependencies.rb (that basically lists all the components you're using), init.rb (that specifies your choice of ORM, test framework, and template framework), and database.yml (that, as in rails, provides database config).

Right now, everything merb generates for us looks fine, so we'll stick with it.

Creating the model

It's time to create a model. Issue the command (inside blog/),
$ merb-gen model post

to create model Post. It'll be in app/models/post.rb.

In rails, you'll only have to write migration and model specification (e.g., all the columns) will be automatically read from the database. With DataMapper, we have to specify the model's properties inside its class definition. Out Post model looks like this:

class Post
include DataMapper::Resource

property :id, Serial
property :title, String
property :body, String

After that, we have to work with the database to create the table for it. For simple property changes (e.g., adding a new model or adding properties), you don't have to write any migration as merb is clever enough to do that for you: just call
$ rake db:autoupgrade

There's another option for migrating table structures, rake db:automigrate, but this rake task also deletes all your old data (it is destructive), so I prefer db:autoupgrade.

Merb has an interactive console that we can play will models, so let's try to add some post to our blog before moving on.
$ merb -i
irb(main):001:0> p = :title => 'Hello!', :body => 'This is my first post'
=> #<Post id=nil title="Hello!" body="This is my first post">
~ INSERT INTO "posts" ("title", "body") VALUES ('Hello!', 'This is my first post')
=> true
irb(main):003:0> p2 = Post.create :title => 'Second post', :body => 'what??'
~ INSERT INTO "posts" ("title", "body") VALUES ('Second post', 'what??')
=> #<Post id=2 title="Second post" body="what??">

Creating the controller

Okay, we have something to display now. Let's create a controller. Call
$ merb-gen controller posts

This command generates app/controllers/posts.rb. Note that there's no Controller suffix to the name. Let's add something to method index.

class Posts < Application
def index
@posts = Post.all

In merb, you have to call render explicitly. This would render a default view for this action. Another point to note is that instead of using Post.find(:all) with Active Record, in Datamapper you only have to call Post.all.

Let's create a view for this action. We can edit views/posts/index.html.erb like this:
<h1>My posts</h1>
<% for post in @posts %>
<h2><%= post.title %></h2>
<p><%= post.body %></p>
<% end %>

It's time to see the posts! Run
$ merb

then point your browser to http://localhost:4000/posts or

New posts

Let's create a new post! We'll add a link "add new post" at the bottom of the index page.
<%= link_to 'add new post', url(:controller => :posts, :action => :new) %>

Method url, that returns a url for an action, can be really fancy, but for now we go with a simple rails-like version.

Then create methods new in Posts controller that render the view.

class Posts < Application
# ...
def new
@post =

Also, the view new.html.erb in app/views/posts:
<h1>Creating new post</h1>
<%= form_for @post, :action => 'create' do %>
<%= text_field :title, :label => 'Title' %><br/>
<%= text_area :body, :label => 'Body' %><br/>
<%= submit 'New post' %>
<% end =%>

Note that we use form_for and methods text_field and text_area know that it is inside this form automatically. (In rails you'd need the block parameter.)

Finally, we add method create to Posts controller:

class Posts < Application
# ...
def create
@post = params[:post]
redirect url(:action => 'index')

Try it to see if you can create new posts.


What kind of blogs without comments?

So we'll create the comment model. Call
$ merb-gen model comment

and edit app/models/comment.rb:

class Comment
include DataMapper::Resource

property :id, Serial
property :body, String

We have to tell a Post that it has many comments. We'll do this by adding something like has_many in Active Record to the model:

class Post
# ...
has n, :comments

This is how you specify one-to-many association in Datamapper. If you want one, just use has 1, :comment.

Now let's turn to view and controller. Edit app/views/posts/index.html.erb by adding comment listing and new comment form.
<h1>My posts</h1>
<% for post in @posts %>
<h2><%= post.title %></h2>
<p><%= post.body %></p>
<% post.comments.each do |comment| %>
<li><%= comment.body %></li>
<% end %>
<%= form_for, :action => url(:controller => 'posts',
:action => 'create_comment',
:id => do %>
<%= text_field :body %>
<%= submit 'New comment' %>
<% end =%>
<% end %>

<%= link_to 'add new post', url(:controller => :posts, :action => :new) %>

I believe that with merb router, we can write a better the action url. I'll update this entry after I find out how. Also, note that to get the list display correctly, I have to delete the merb stylesheet link line in app/views/layout/application.html.erb because it hides my list items.

To handle this action, we create method create_comment in Posts controller.

class Posts < Application
# ...
def create_comment
post = Post[params[:id]]
comment = params[:comment]
post.comments << comment
redirect url(:action => 'index')

Note the way we find a post by id (Post[params[:id]]).

Hope this blog post help getting you started with merb and Datamapper. Any comments are welcome!



Dean said...

greetings to all.
I would first like to thank the writers of this blog by sharing information, a few years ago I read a book called guanacaste costa rica in this book deal with questions like this one.

niz said...

Hello .. firstly I would like to send greetings to all readers. After this, I recognize the content so interesting about this article. For me personally I liked all the information. I would like to know of cases like this more often. In my personal experience I might mention a book called Generic Viagra in this book that I mentioned have very interesting topics, and also you have much to do with the main theme of this article.

office 2007 enterprise key said...

I've recently started a blog, the information you provide on this site has helped me tremendously. Thank you for all of your time & work.

Anonymous said...

Excellent work! The information presented was very helpful. I am hoping that you carry on with the great job executed.
Bridgeport CT Locksmith
Locksmith Nashville TN
Berkeley locksmith
Locksmith Palo Alto CA
Locksmith Sunnyvale CA
Locksmith RedwoodCity
miami locksmith
hialeah locksmith
miami locksmiths
aventura locksmith
Hialeah FL Locksmith
locksmith fort worth
locksmith in hialeah
Aventura FL locksmith
pembroke pines locksmiths
locksmith plano tx
hialeah locksmiths
locksmith aventura
locksmith miami beach fl
locksmith miami
fort worth locksmiths
hialeah locksmiths
locksmith hialeah
locksmith irvine fl
locksmith hialeah fl
locksmith aventura fl
Memphis Locksmiths
Locksmith Memphis TN
Washington Locksmith
Locksmith Washington
Locksmith Memphis
Memphis Locksmith
Corona CA Locksmith