|
2007-12-27 21:53
tutorial, haml, merb, datamapper
merb + datamapper + noob: quick startAuthor: Kacper Cieśla (comboy)Important note: I hope to help somebody setting up a simple merb application, but I’m new to merb too. So I’m sorry if show you something that can be done in some better way. Comments are very appreciated. Merb is a quite new framework, created by Ezra Zygmuntowicz. In many ways it’s similar to ruby on rails, but here core is very small and you can obtain more functionality (if you want to), by installing plugins (as gems). That (and few different things about which you can read here), makes it faster than rails. I assume your basic ruby on rails knowledge for this tutorial. Basic setupOk, so first we need merb. You can just: # gem install merb # gem install mongrel json json_pure erubis mime-types rspec hpricot mocha rubigen haml markaby mailfactory Ruby2Ruby -y # svn co http://svn.devjavu.com/merb/trunk merb # cd merb # rake install That’s it. You have merb. Let’s generate some project: $ merb almost_blog
create
create app/controllers
...
You may want to take a look at the app skeleton generated in amost_blog directory. It’s pretty similar to this generated by rails. But.. Merb is (like Ezra say) “ORM agnostic”. So it’s time to make a choice. You can choose between activerecord (one that rails uses), sequel and datamapper. My subjective choice is datamapper. datamapperFirst we need to get it. The easiest way: $ gem install datamapper merb_datamapper However I had some problems until I installed it from trunk: $ svn co http://datamapper.rubyforge.org/svn/trunk/ data_mapper And for datamapper you need drivers for your database choose a gem to install:
I’ve chosen bad old ugly MySQL that I got used to (gem install do_mysql) It’s time to tell your merb app about your choice. In config/dependencies.rb uncomment the following line: use_orm :datamapper
save file, and in main app directory (amost_blog in this example) hit: $ rake No database.yml file found in /lapciak/project/tmp/almost_blog/config. A sample file was created called database.sample.yml for you to copy and edit. You know what to do. My version of config/database.yml looks like this: --- # This is a sample database file for the DataMapper ORM :development: &defaults :adapter: mysql :database: almost_blog_dev :username: looser :password: nopass :host: localhost :test: <<: *defaults :database: sample_test :production: <<: *defaults :database: sample_production And our basic setup is done. ModelsWe’ll try some blog-like app $ script/generate model note
Started merb_init.rb ...
Connecting to database...
Thu, 27 Dec 2007 21:01:33 GMT: loading gem 'merb_datamapper' from config/dependencies.rb:13 ...
Loading Application...
Compiling routes..
Loaded DEVELOPMENT Environment...
exists app/models
create app/models/note.rb
dependency merb_model_test
exists spec/models
create spec/models/note_spec.rb
As you can guess, knowing that you use datamapper, merb generated appropriate model files. When you’re sill in console type:$ script/generate model comment Now using your favourite editor (wow, you’re using netbeans too?!) open app/models/note.rb And here, some basic datamapper knowledge is needed. But I’ll give you some finished model file, and you probably won’t have a problem understaing it. class Note < DataMapper::Base property :title, :string property :body, :text property :created_at, :datetime has_many :comments validates_presence_of :title end As you can see fields are defined in the model file, and there are rails-like helper methods to create associations and validations. Also, created_at is a magic field that is autoupdated to current time on record creation. You probably can’t wait to see it working so let’s type in console: $ rake dm:db:automigrate And take a look how your database schema looks like now. Let’s finally talk with merb $ merb -i As you no doubt have guess it’s something similar to script/console in rails Sample chat session: $ merb -i Started merb_init.rb ... Connecting to database... Thu, 27 Dec 2007 21:19:57 GMT: loading gem 'merb_datamapper' from config/dependencies.rb:13 ... Loading Application... Compiling routes.. Loaded DEVELOPMENT Environment... Not Using Sessions irb(main):001:0> Note.find(:all) => [] irb(main):002:0> n = Note.new => #<Note:0x..fb6bd77f0 @new_record=true, @created_at=nil, @body=nil, @title=nil, @id=nil> irb(main):003:0> n.body = 'blah blah' => "blah blah" irb(main):004:0> n.save => false irb(main):005:0> n.errors => #<Validatable::Errors:0xb6bcc8b4 @errors={:title=>["Title must not be blank"]}> irb(main):006:0> n.title = 'wasssssup' => "wasssssup" irb(main):007:0> n.save => true irb(main):008:0> Note.find(:all) => [#<Note:0x..fb6b9f3a0 @new_record=false, @created_at=#<DateTime: 212065554103/86400,0,2299161>, @body="blah blah", @title="wasssssup", @id=1>] irb(main):009:0> Done with talking, time for a comment model now (app/models/comment.rb): class Comment < DataMapper::Base property :name, :string property :body, :text property :created_at, :datetime belongs_to :note validates_presence_of :name, :body end and automigration: dm:db:automigrate and.. oooopss – If you had any notes saved, they are all gone. That’s the one painful thing about datamapper. It’s not able to ALTER your tables. Instead, it recreates them every time you do automigrate. So you better modify your tables manually in the production environment. Anyway, you have now schema for your models in your database. controllersGeneration: script/generate controller notes And just by the template you can tell the first difference: class Notes < Application def index render end end Yes, you have to call render manually. Whatever you return from controller method goes to the browser output. It may be a good moment now to finally see our application in action. To run the server you just type: $ merb in the main application directory. It will start on port 4000, so you can check the http://localhost:4000/notes/ to see auto generated index template for notes. If you are a good observer, you will notice that in the page source there is something more than you can find in views/notes/index.html.erb. There is already a default application layout in views/layouts/applicaiton.html.erb We’ll try to list some notes first (you can create them manually using merb console “merb -i”). Controller part is simple: class Notes < Application def index @notes = Note.find(:all) render end end but let’s take a look at viewYou’ve already seen the template, It’s a simple erb (note that merb uses erubis for .erb templates by default). Example template for index would look like this: <h1>Blah blah notes</h1> <table cellspacing="10" style="border: 1px solid #555"> <% for note in @notes %> <tr> <td><%= note.title %></td> <td><%= link_to 'show', "notes/#{note.id}"%> </td> <td><%= link_to 'edit', "notes/#{note.id}/edit"%></td> </tr> <% end %> </table> Notice that second parameter for link_to method is just an url string. It seems that’s the way it works here, but there is a workaround for it that I’ll show later. So it works. But I do like HAML. It’s a little slower, but it looks so much better. To get haml working with your merb application first you need to install it: # gem install haml Then tell your merb app that you like haml. In config/dependencies.rb add: dependency 'haml'
And now you can delete index.html.erb and put so much nicer index.html.haml indstead: %h1 Blah blah notes %table{:cellspacing => 10, :style => 'border: 1px solid #555'} - for note in @notes %tr %td= note.title %td= link_to 'show', "notes/#{note.id}" %td= link_to 'edit', "notes/#{note.id}/edit" (Don’t forget to restart the server to let merb load dependencies). Now about this link_to. If you don’t want to put urls manually, well, merb is already pretty RESTful, first go to config/router.rb, you will need something like this: puts "Compiling routes.." Merb::Router.prepare do |r| r.resources :notes r.default_routes end Routes in merb are compiled, and this puts here teached me some useful thing: when you’re in development, routes are being recompiled every time you change something in router.rb. Nice. Time to use our router now, after modification you’ve just made, you can change your links to: %td= link_to 'show', url(:note,note) %td= link_to 'edit', url(:edit_note,note) Looks much better. Time to make a page for adding a new note. You may want to modify your application layout to add some links on the top: <%= link_to 'list', url(:notes) %> | <%= link_to 'add new note', url(:new_note) %> <hr /> (yeah, I was too lazy to rewrite it to haml), and now we create a view for new note. There we’ll be some magic there – this is my finished view: %h1 Adding a new note = error_messages_for @note - form_for(@note, :action => url(:note)) do = text_control :title, :label => 'Title' %br = text_area_control :body, :label => 'Body' %br = submit_button 'Save' But it won’t work for you. Even if you use form_tag instead of form_for. As I already mentioned, Ezra wants to keep merb core as small as possible. For form helpers, you need a plugin: # gem install merb_helpers and new line in your config/dependencies.rb: dependency 'merb_helpers'
(restart) And the controller part for this view is: def new @note = Note.new render end (yeah, I know). Now let me try explain (myself): there is a form_tag and there is a text_field in helpers, but form_for seems to be more elegant. Also, _field methods seems to be adequate to _field_tag methods from rails. So they’re good when you need to get a single value from user, but they’re not so elegant when creating a form for an object that’s defined as a model. form_for created a block, and inside this block all _control methods add fields inside an object that this form is for Now, I’ve tried something like: - form_for(:note, :action => url(:note)) do (just like in documentation) but it does not work. It works when I provide an empty object as a first argument. That’s why I’m creating it in the controller. (Uh… The worst part over, now let’s just finish this almost_blog) If you try to add some note now you’ll get an error about “create” method not found. So in controllers/notes.rb: def create @note = Note.new(params[:note]) if @note.save redirect url(:note,@note) else render :action =>'new' end end def show @note = Note.find(params[:id]) render end We’ll need a show method too, so here you got some example view for it: %h1= @note.title %p= @note.body And now adding new note should work. Check what happens if you try to add note without a title. To make errors look better you would need to add some css, notice that all fields with errors have element class set to “error” Editing note is very simple, but we don’t want to duplicate form we created, so let’s try like this:
And note editing is done :) Last part is being able to comment the note. Let’s just implement it without too much talking: views/notes/show.html.haml: %h1= @note.title %p= @note.body %b Comments: %br %br - if @note.comments.size == 0 %i No comments yet - for comment in @note.comments = partial :comment, :with => comment %br %br %b Leave a comment %br = error_messages_for @comment if @comment - form_for((@comment || Comment.new), :action => "add_comment") do = hidden_field :name => :note_id, :value => @note.id = text_control :name, :label => 'Your name:' %br = text_area_control :body, :label => 'Comment:' %br = submit_button 'Add comment' Because of my solution for new/edit form you might think there are no partials in merb so here is an example of their usage. views/notes/_comment.html.haml %b= comment.name %p= comment.body %hr And the controller part: def add_comment @note = Note.find(params[:note_id]) @comment = Comment.new(params[:comment].merge(:note => @note)) if @comment.save redirect url(:note,@note) else render :action => 'show', :id => @note.id end end And we’re done. It’s still lacking some basic features like deleting comments and notes, but it’s just an example (and it works) Complete project source for lazy people ;) SummaryFirst of all merb is lacking a good documentation. For example to check how to pass an object to partial, I had to check the source. In fact, most of the things must be checked in the source. That makes it a little bit hard to learn, and that’s why I wrote this crap. Merb architecture seems to be well thought. There is less magic, that’s why on the beginning you may wonder why form_tag does not work. It may be a good choice if you care about speed, don’t need some fireworks like RJS and lots of helpers. It seems to be perfect for writing a webservice. Well, I think we’ll see in about year how it’s developing and how it’s getting better (and I think it’s not only about what Ezra will do, but mainly about what community will do) As always, I have to sorry for my enligsh and all mistakes I’ve made. And once again, you’re comment are extremely appreciated.
rate this page:
6.18 (31 votes )
|
ver. 0.1.93 alpha (bugtrack, feature requests) Author of this page about himself::
Student AGH (4 rok), autor programuj.com oraz skryptu do tego community. Po jakichś 6 latach PHP przerzuciłem się na Ruby i Railsy. Obecnie zajmuje się głównie frameworlami www, wcześniej pomacałem...
Stats (last 14 days):
Kto linka podrzucał (alpha test shit escape):
Share it:
Who's online:
|