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 1.0.6.1 (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
Because we'll use datamapper and sqlite3:
Start by generating merb application:
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.
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:
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.
This command generates app/controllers/posts.rb. Note that there's no Controller suffix to the name. Let's add something to method index.
It's time to see the posts! Run
then point your browser to http://localhost:4000/posts or http://127.0.0.1:4000/posts.
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.
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:
and edit app/models/comment.rb:
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.
$ sudo gem install merb
$ sudo gem install datamapper merb_datamapper do_sqlite3
$ merb-gen app blog
Creating the model
It's time to create a model. Issue the command (inside blog/),$ merb-gen model post
class Post include DataMapper::Resource property :id, Serial property :title, String property :body, String endAfter 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
$ merb -i irb(main):001:0> p = Post.new :title => 'Hello!', :body => 'This is my first post' => #<Post id=nil title="Hello!" body="This is my first post"> irb(main):002:0> p.save ~ 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
class Posts < Application def index @posts = Post.all render end endIn 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 %>
$ merb
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) %>
class Posts < Application # ... def new @post = Post.new render end endAlso, 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 =%>
class Posts < Application # ... def create @post = Post.new params[:post] @post.save redirect url(:action => 'index') end endTry it to see if you can create new posts.
Comments
What kind of blogs without comments? So we'll create the comment model. Call$ merb-gen model comment
class Comment include DataMapper::Resource property :id, Serial property :body, String endWe 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 endThis 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> <ul> <% post.comments.each do |comment| %> <li><%= comment.body %></li> <% end %> <li> <%= form_for Comment.new, :action => url(:controller => 'posts', :action => 'create_comment', :id => post.id) do %> <%= text_field :body %> <%= submit 'New comment' %> <% end =%> </li> </ul> <% end %> <%= link_to 'add new post', url(:controller => :posts, :action => :new) %>
class Posts < Application # ... def create_comment post = Post[params[:id]] comment = Comment.new params[:comment] post.comments << comment post.save redirect url(:action => 'index') end endNote 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! ฉบับภาษาไทย