merb 0.9.5 + haml + datamapper + sqlite3
Since Merb is constantly changing prior to its 1.0 release, a lot of the tutorials did not work exactly the way I expected them to work.
I was looking for a tutorial that covered a simple Merb + HAML + DataMapper + SQLite application. I found that a good candidate to tweak was the simple chat wall tutorial that was prominently linked on the Merb wiki. The following are some code updates to get it working with Merb 0.9.5, HAML, DataMapper, and SQLite. Feedback is welcome.
merb-gen app
merb-gen app allows you to specify the template engine, ORM, and testing framework directly on the command line:
merb-gen app slapp --template-engine haml --orm datamapper --testing-framework rspec
init.rb
DataMapper dependencies should be specified ininit.rb to get counts/aggregates, automatic created_at timestamps, and validations. Datamapper can also handle session storage. And don't forget to set the :session_id_key!
init.rb contents
[sourcecode="ruby"]
dependency "dm-aggregates"
dependency "dm-timestamps"
dependency "dm-validations"
dependency "merb_helpers"
...
use_orm :datamapper
...
use_template_engine :haml
...
c[:session_id_key] = 'chat_wall_session_id'
...
c[:session_store] = 'datamapper'
...
[/sourcecode]
SQLite database configuration and setup
DataMapper offers a rake task to create a sample database.yml file:rake dm:db:database_yaml
Here's what a database.yml file for development and test SQLite databases looks like:
database.yml contents
[sourcecode="ruby"]
---
:development: &defaults
:adapter: sqlite3
:database: db/dev.db
:test:
sqlite db/dev.db
sqlite db/test.db
Database sessions migration:
rake dm:sessions:create
Database migration:
rake dm:db:automigrate
Post model
Model validations didn't seem to be working properly...post.rb contents
[sourcecode="ruby"]
class Post
include DataMapper::Resource
property :id, Serial
property :body, String
property :created_at, DateTime
validates_length :body, :minimum => 2
end
[/sourcecode]
HAML
I had problems with the Merb form helper in the index HAML file...app/views/posts/index.html.haml contents
[sourcecode="ruby"]
!!! Loose
%html{html_attrs{'en-us'}}
%body
%h1 Welcome to Slapp
%h2 A simple chat wall
%p Recent Posts:
.container{:id => 'posts'}= partial("shared/post", :with => @posts)
%div Post Something:
- #form_for(:post, :action => url(:posts) ) do
%form{ :action => '/posts/create', :method => :post}
= text_field(:name => "body", :size => 40)
= submit "Post Message!"
[/sourcecode]The individual post HAML file...
app/views/shared/_post.html.haml contents
[sourcecode="ruby"]
.post{:id => 'post-' + post.id.to_s}
.body= h(post.body)
.created= relative_date(post.created_at)
[/sourcecode]
RSpec
Lastly, I had to change some of the CSS selectors and the deletion method for the index spec...spec/views/posts/index_spec.rb contents
[sourcecode="ruby"]
...
it "should have a containing div for the posts" do
@body.should have_selector("div#posts.container")
end
it "should have a div for each individual post" do
@posts.each do |post|
@body.should have_selector("div#posts.container div#post-#{ post.id }.post")
end
end
it "should have the contents of each post inside a div with an id and class" do
@posts.each do |post|
@body.should have_tag("div#posts") do
with_tag(:div, :id => "post-#{ post.id }", :class => "post", :content => post.body)
end
end
end
it "should have a form to create new posts with a single input and submit button" do
@body.should have_selector("form[@action='/posts/create']")
@body.should have_selector("form[@action='/posts/create'] input[@name='body']")
@body.should have_selector("form[@action='/posts/create'] input[@type='submit']")
end
after(:each) do
Post.all.destroy!
end
...
[/sourcecode]