Merb 0.9 on Ubuntu Linux 7.10
The Merb application framework is getting close to a 1.0 release. Merb takes many of the ideas of Ruby on Rails and does them one better. RoR was designed for developers and applications, but has not been the best to run in production. Merb was written from the ground up with performance and scalability. But as a result, its like travelling abroad in that things are similar but not exactly the same as you are used to developing with RoR.
The platform of choice of most rubyists these days is OS X, with its fine unixy-goodness and groovy Textmate editor. Ubuntu Linux provides most of these features for a fraction of the price! Also, since these applications are generally deployed on the Linux OS, it makes sense to know how to get things running on that platform as well. Let’s roll up our sleeves and get to work.
I used Justin’s post as a starting point on what to do. Open up a terminal window and start.
Get the Git
First, we install the git version control system which merb uses. Note the current Debian git package has a minor bug requiring the /etc/mailname file. Create that file with your hostname in it for now.
sudo apt-get install git-core vi /etc/mailname
Gems
I assume you have been using Ruby before and have a modern Ruby and RubyGems installed. If not, go do that now. I’ll wait.
Justin recommends having these gems. All seem a good idea, but mongrel erubus and rspec seem more necessary if you are trying to cut down. Merb requires rack, and a ORM like Rails’ ActiveRecord, Sequel, or Datamapper, which it looks like it prefers. Merb is built upon the Rack web server abstraction library.
Like Merb, Datamapper is thread-safe to allow multiple requests being handled. However, it is not yet fully developed like ActiveRecord and may not be as production-ready. If you are porting an application from Rails, you may want to continue using ActiveRecord.
sudo gem install mongrel json json_pure erubis mime-types rspec hpricot mocha rubigen haml markaby mailfactory Ruby2Ruby -y sudo gem install rack sudo gem install datamapper -y
Install Merb
Merb is available in gem form, but they may not be as up to date as we would like. So let’s git them from the git repository. If you are having problems, try the http:// protocol instead of the git:// protocol. Merb in divided up into merb-core, merb-more, and merb-plugins in order to let you craft the server with just the parts you need. We need to go into each repository and “install” it in your gems.
mkdir trymerb cd trymerb git clone git://github.com/wycats/merb-core.git git clone git://github.com/wycats/merb-more.git git clone git://github.com/wycats/merb-plugins.git cd merb-core sudo rake install cd ../merb-more sudo rake install # has link_to, etc cd ../merge-assets sudo rake install cd ../../merb-plugins/merb_helpers/ sudo rake install cd ../merb_activerecord/ sudo rake install cd ../merb_datamapper/ sudo rake install cd ../merb_rspec/ sudo rake install
Whew! That’s going to get old fast. The upcoming gems will be better.
Merb with PostgreSQL
PostgreSQL is my RDBMS of choice. MySQL would work similarly. Ubuntu needs your PostgreSQL header files, so we load them first.
sudo apt-get install libpq-dev sudo gem install do_postgres
Now let’s go roll an app!
The MyBlog Merb Application
To show off our merby goodness, we will build the “hello world” of ruby web applications, the blog.
cd trymerb merb-gen myblog cd myblog createdb myblog_development
The createdb command is for postgresql, please substitute the create database for your db of choice.
Edit config/init.rb file and enable the following configurations.### Uncomment for DataMapper ORM use_orm :datamapper use_test :rspec ### Add your other dependencies here dependencies "merb_helpers", "merb-assets"Now create your /config/database.yml
---
# This is a sample database file for the DataMapper ORM
:development: &defaults
:adapter: postgresql
:database: myblog_development
:username: the_user
:password: secrets
:host: localhost
:test:
<<: *defaults
:database: myblog_test
:production:
<<: *defaults
:database: myblog_production
Merbful Authentication
Optionally, we add in authentication, the “Restful Authentication” plugin port to merb. Read me about here
cd trymerb git clone git://github.com/hassox/restful-authentication.git cd restful-authentication git checkout -b merbful_authentication origin/merbful_authentication sudo rake install cd trymerb/myblog merb-gen authenticated user_model session_controller
Our post resource
Restful merb resource that is. This creates the controller, model, and view. If you are using ActiveRecord, I would also expect a migration. For Datamapper, the columns are defined in the model. Use rake to create the tables from the model. (For Postgres, use the datetime type instead of the timestamp type you would use in Rails.)merb-gen resource post title:string content:text created_at:datetime rake dm:db:automigrateEdit config/router.rb to enable these actions:
# RESTful routes
r.resources :posts
# Change this for your home page to be available at /
r.match('/').to(:controller => 'posts', :action =>'index')
Starting Merb
Open a new terminal window and start merb from your app directorycd trymerb/myblog merbNow point your brower to http://localhost:4000/ and you should be able to see it. The resource generator does not yet build the ERB files out like Rails’ scaffolding. So we have to write that ourselves.
Note that this is where some of the differences between Rails and Merb shows up. Merb has its own routing using the url() helper. Read more about it here .
url(:posts) #=> "/posts" url(:new_post) #=> "/posts/new" @post = Post[1] url(:post, @post) #=> "/posts/1"Edit the app/views/posts/index.html.erb and add in a simple post listing.
<h1>My Blog</h1> <% @posts.each do |n| %> <h2><%= n.title %></h2> <div2><%= n.content %></div> <% end %> <div> <%= link_to "Write new", url(:new_post) %> </div>
Edit the app/views/posts/new.html.erb and add in the compose form. Feel free to embellish your HTML. I added the hidden field to remember how to do it if I need to figure it out again.
As you see, the field control helpers are different, but self-explanatory. They were actually the hardest part to figure out since they needed to be installed from the proper repository and enabled in the init.rb file. The source code also shows more of what you need to do.
<h1>Write a new post</h1>
<%= error_messages_for :post %>
<% form_for(@post, :action=>url(:posts), :method=>"post") do %>
<%= hidden_field :name=>:wave, :value=>'hello' %>
<%= text_control :title, :label=>"Title", :size=>50,
:maxlength=>250, :style=>"font-weight:bold;" %>
<br /><%= text_area_control :content, :label=>"Rant", :rows=>15, :cols=>50 %>
<br /><%= submit_button "Save" %>
<% end %>
That should do it! Enjoy your new merb blog app.
More Things with merb
The Merb console
The merb object has some things worth exploring, like the app object in Rails.merb -i irb(main):001:0> merb.show_routes
Debugger
Like with Rails 2.0, call the “debugger” function where you want a breakpoint. and start merb like this:merb -D
Merb on Thin
You can run the Thin web server with Merb.sudo gem install thin merb -a thin
Disclaimer
This was my first experiment using Merb on Ubuntu, and I am thrilled that it works so well already. This is not quite a recipe for starting from scratch. Some instructions may be convoluted, unnnecessary, copied here incorrectly, or just plain wrong.
Merb is the exciting new direction for developing ruby applications. Ezra is addressing the shortcomings we have in developing and deploying robust applications in ruby. The Rubinius and Merb projects are doing a lot to make this happen.
Email on Rails
I am giving a talk this evening at the Philly On Rails meeting on an introduction to email and sending and receiving email with a Ruby on Rails application.
I am referencing the slides and a sample application in case anyone needs to reference them!
Email Basics
What is email exactly? It is quite different from the view we see in our MUA, (Thunderbird, gmail, mutt, pine, etc.). Let’s review the basic of email mechanics, shall we?
Email consists on an Envelope and the Message Data. The envelope is
- Return Path: The email address to return the message if undeliverable
- Recipients: The email address(es) of the recipients of the message
The Message Data is the meat of the mail,
- RFC822 Headers such as Subject, From, To, Date, etc. Headers can span multiple lines by starting the subsequent line with a white-space. A blank line signals the end of the header and the start of the body follows. Non-standard header names begin with the “X-” prefix, used to denote experimental features. These usually have meaning only to the software that placed them there.
- Body, text, html, etc. Using the MIME standard, the body can be made to include alternate versions of the message based on markup, and also attach files to the message.
- File Attachments. Usually, binary files are encoded in Base64 no non-printable characters. This increases the file size by about 33% when encoded in the message.
Note that the From and To headers in the headers are really informational. It is the envelope recipient list that determines who it was from.
Also, since the From header can be virtually anything, it is easy to spoof the sender or even the full message. Even the recipient return path can be bogus. Therefore, email is not secure as such (except for PGP/GPG signings), and should not be trusted outright.
Since each email server that passes the message along prepends a Received header to the top of the message, you can generally trace its path to see if it came from a source server that is a proper MTA for the sender. Of course, you can only trust the received headers from servers as far back as you trust; they can also be tampered with.
To: you@example.com
From: me@example.com
Date: 20 Jul 2007 09:21:51 -0700
Message-ID: <521.1090340511@example.com>
Subject: Simple Email Message
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas
ultrices sem sed urna accumsan cursus.
Content-Type and MIME Types
When you want to create more complex email messages, say with alternative content or attachments, you need to construct your message using MIME containers and body parts.
- Content-Type: Use this header in your email message to identify the MIME type of your content
- text/plain is the default MIME type of email. This is viewable by all mail clients.
- text/html denotes an HTML formatted body or part. This is only viewable in GUI-based clients that support HTML.
- multipart/alternative is a MIME container that holds the text, HTML or other versions of the main message. Only one of these (the best one it can show) is viewable by the user’s mail client.
- multipart/alternative is a MIME container used for attaching files to the message body. The first part is the body part (which can also be another container), and the rest are attachments.
- multipart/related is a MIME container that wraps included graphics referenced from an HTML body. These graphics are shown “in place”, such as a logo in the letterhead, instead of being seen as attachments.
- The boundary parameter of the Content-Type header is used to provide a unique identifier to define the start and end of the body parts within a MIME container. Lines starting with two hyphens followed by the boundary value is the split point in the message. The final boundary line is the two hyphens, boundary value, and two more hyphens.
- image/png is a PNG graphic file, also a image/gif or image/jpeg could be used.
- application/pdf is a pdf attachment, which could be any application-defined file
- Stir to combine…
Each MIME body part (attachment, container, or message version) itself has a small MIME header set to indicate its content-type, encoding, and other information.
Here is an example message that is composed of a text and HTML body alternatives, with an image attachment called out from the HTML version, plus another image as a regular attachment. The structure of the MIME parts is
multipart/mixed (Holds the body part plus attachments)
multipart/alternative (groups the different version of the message body)
text/plain
multipart/related (groups the HTML part with images it references)
text/html
image/jpeg
image/png (attachment)
Here is how this looks in the email message.
To: you@example.com
From: me@example.com
Date: 20 Jul 2007 09:21:51 -0700
Message-ID: <521.1090340511@example.com>
Subject: Complex Email Message
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="mm001"
This is a multi-part message in MIME format.
--mm001
Content-Type: multipart-alternative; boundary=mb001
--ma001
Content-Type: text/plain
This is the plain text body
--ma001
Content-Type: multipart-related; boundary="mr001"
--mr001
Content-Type: text/html
Content-Transfer-Encoding: quoted-printable
This is the <em>HTML</em> body
<IMG=20SRC=3D"No%20AttachName"=20alt=3D"Picture=20(Metafile)">
--mr001
Content-Type: image/jpeg; name="logo.jpg"
Content-Transfer-Encoding: base64
Content-Description: Picture (Metafile)
Content-Location: No%20AttachName
Qk2ewgIAAAAAADYAAAAoAAAAJAIAAG4AAAABABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////
....
--mr001--
--ma001--
--mm001
Content-Type: image/png;
name="elroy-jetson.png"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="elroy-jetson.png"
R0lGODlhMgAvAPcAAAAAAJQAAPfOjP//////////////////////////////////////////////
.....
--mm001--
Content-Transfer-Encoding
Note the use of quoted-printable in the above HTML segment. Quoted-printable encoding escapes special characters with an equal symbol (=) followed by the 2-character hexadecimal ASCII representation of the character value. For example, any equal symbols in the body are replaced with ”=3D”, where 3D is the hexadecimal representation of the equal symbol in the ASCII collating sequence.
Web browsers do something similar when sending special characters in the URL, but using a percent (%) symbol as the escape symbol.
Quoted-printable also wraps text so lines do not become too long. An equal symbol at the end of the line (=\n) indicates the line is wrapped. Email standards define the maximum length of a line to be 77 (?) characters, but since this is not a hard limit, most email software is flexible about this limit.
Binary files are usually encoded in Base64. The Base64 method maps every 6 bits to a printable character. Ruby has a Base64 helper class
require "base64"
enc = Base64.encode64('Send reinforcements') # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
plain = Base64.decode64(enc) # -> "Send reinforcements"
SMTP: How Email is Tranferred
Email is delivered via SMTP, Simple Mail Transport Protocol. This is a simple state-machine which accepts email through a “command line” interface, usually over port 25. Open a telnet connection to any MX(mail exchanger) host on port 25 to try your hand at delivering a mail manually.
Here you can really see that the email envelope is powerful, it requires 3 part of the email message:- Return Path (MAIL FROM)
- Recipients: (RCPT TO)
- Message: (DATA), which is ended by a single period on the last line.
220 example.com mailfront ESMTP
MAIL FROM: <me@yahoo.com>
250 2.1.0 Sender accepted.
RCPT TO: <you@example.org>
250 OK
DATA
354 End your message with a period on a line by itself.
Subject: Hello there
From: Me <me@yahoo.com>
I just love SMTP!
.
250 2.6.0 Accepted message qp 16590 bytes 226
QUIT
221 2.0.0 Good bye.
The new Girders blog
Alt-Ctrl-Delete!
A new blog, new host, new language (ruby), and new blog software (mephisto).