Ramaze and ActiveRecord

Posted by Michael on February 4, 2009 in General, Programming, Ruby Language

Thanks to the great folks on IRC over at Freenode#ramaze, I was able to not only get Ramaze working with Erubis and Activerecord for a pseudo apples to apples comparison of Rails vs. Ramaze performance benching, but I was also able to get Apache 2.2.9 talking to Passenger to Ramaze. This quick post will take you through the basics.

Environment

This post will guide you through setting up the following environment on Ubuntu Intrepid (8.10):

To get started:

sudo apt-get install apache2 passenger
sudo passenger-install-apache2-module

Install the Rack, Ramaze, Activerecord, and Erubis gems

sudo gem install rack, ramaze, activerecord, erubis

Establishing Project

Now create your first ramaze project with:

ramaze --create demo

Then change to the demo directory. If you see a start.ru file, rename it to config.ru or Passenger won’t find it. Create a file called passenger.rb with the following:

require 'rubygems'
require 'ramaze'

# Add directory start.rb is in to the load path, so you can run the app from
# any other working path
$LOAD_PATH.unshift(__DIR__)

# Initialize controllers and models
require 'controller/init'
require 'model/init'

Ramaze::Global.sourcereload = false
Ramaze::Global.sessions = true
Ramaze::Log.ignored_tags = [:debug, :info]

Important: Do not include “Ramaze.start …” in this file or this will surely mess things up for Passenger.

Now edit the config.ru file (formerly start.ru):

/usr/bin/env rackup
# start.ru for ramaze apps
# use thin>=0.6.3
# thin start -r start.ru
#
# rackup is a useful tool for running Rack applications, which uses the
# Rack::Builder DSL to configure middleware and build up applications easily.
#
# rackup automatically figures out the environment it is run in, and runs your
# application as FastCGI, CGI, or standalone with Mongrel or WEBrick�..all from
# the same configuration.

require 'app'
Ramaze.trait[:essentials].delete Ramaze::Adapter
Ramaze.start
run Ramaze::Adapter::Base

Add the following virtual host file to /etc/apache2/sites-enabled/001-ramaze-demo

<VirtualHost *:80>
    ServerName ramaze.demo.local
    RackBaseURI /
    RailsAutoDetect off
    RackAutoDetect on
    DocumentRoot /var/www/ramaze/demo/public
</VirtualHost>

And edit your /etc/hosts file to include “ramaze.demo.local” so it resolves to localhost.

Database

Next, create a database called ramaze_demo (or your choice) and add a posts table and
some data via SQL or migrate scripts (this being a minimal demonstration and all that).

create table posts (
    id        int(11) not null auto_increment
  , title     varchar(255) not null
  , body      varchar(1024) not null
  , primary key (id)
);

insert posts values (1, "First Post", "Thank hrnt for getting passenger talking to ramaze.");
insert posts values (2, "Another Post", "Ask Pistos what SelfMarks is, because he is bored with diigo");
insert posts values (3, "IRC, you say?", "Visit #ramaze on Freenode");

Model

Edit the model.init.rb file with the following:

require 'activerecord'
require 'cleanup_connection_patch'

  ActiveRecord::Base.establish_connection(
    :adapter  => "mysql",
    :database => "ramaze_demo",
    :host     => "localhost",
    :username => "root",
    :password => "secret"
  )

class Post < ActiveRecord::Base
end

Important: cleanup_connection_patch comes from github.com and makes the ActiveRecord behave correctly in a threaded environment. Please see Monkey patching ActiveRecord to automatically release connections « coderrr for more information.

Controller

With the model squared away, time to turn our attention to the controller. Edit controller/init.rb:

class Controller < Ramaze::Controller
  layout '/page'
  helper :x html
  engine :Erubis
end

class PostsController < Controller
  def index
    @posts = Post.find(:all)
  end
end

View

Create a folder under view for posts and add the following Erubis template view/posts.rhtml:

<h1>Listing Posts</h1>

<ul>
  <% for post in @posts %>
      <li><%= A(post.title, :href => "/post/#{post.id}", :title => post.body) %></li>
  <% end %>
</ul>

Note: that while Rails uses filename.html.erb, the Erubis engine expects *.rhtml extension in Ramaze.

Running

Test out the above with webrick, mongrel, or thin with:

ruby start.rb

If all goes well, you should see the three postings above listed.

Launch Apache2, if you haven't already and point your localhost's browser at http://ramaze.demo.local/posts

You should now have a listing of posts rendered through Apache via Passenger.

Conclusion

I am finding much to like about Ramaze, especially after developing with Rails for a few years now and watching it grow at an alarming rate in complexity. Ramaze is a refreshing return to basics. I am finding that Ramaze just may be able to give me most of what I need while giving me a sizeable performance boost in the process. Here's a rails bench on the equivalent of the above:

Concurrency Level:      50
Time taken for tests:   4.277 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      10218492 bytes
HTML transferred:       9595000 bytes
Requests per second:    233.83 [#/sec] (mean)
Time per request:       213.828 [ms] (mean)
Time per request:       4.277 [ms] (mean, across all concurrent requests)
Transfer rate:          2333.42 [Kbytes/sec] received

And this is Ramaze:

Concurrency Level:      50
Time taken for tests:   2.248 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      9815000 bytes
HTML transferred:       9555000 bytes
Requests per second:    444.91 [#/sec] (mean)
Time per request:       112.383 [ms] (mean)
Time per request:       2.248 [ms] (mean, across all concurrent requests)
Transfer rate:          4264.42 [Kbytes/sec] received
  • @trey: Short answer: no for the post; yes for this reply. I tried using erubis by adding a config/initializers/erubis.rb and adding:



    require 'erubis/helpers/rails_helper'
    Erubis::Helpers::RailsHelper.init_properties = { :escape => true, :escapefunc => 'h' }


    With that, I get:


    Concurrency Level: 50
    Time taken for tests: 5.965 seconds
    Complete requests: 1000
    Failed requests: 0
    Write errors: 0
    Total transferred: 13032035 bytes
    HTML transferred: 12407000 bytes
    Requests per second: 167.64 [#/sec] (mean)
    Time per request: 298.266 [ms] (mean)
    Time per request: 5.965 [ms] (mean, across all concurrent requests)
    Transfer rate: 2133.43 [Kbytes/sec] received


    Which is significantly slower than standard erb. I haven’t yet found good info for further tweaking erubis, but if you know the way, please do advise and I will re-run benches.
  • Trey
    Did you use Erubis in rails?
  • kez
    Nice work! I think people have been waiting for something like this for a while; I'm sure there will be a series of never ending rebuttals to this, but great to see your findings.
  • Very cool. It's nice to see an example with ActiveRecord and with the Rails comparison.
  • Awesome, thanks for using/linking to my patch. Lemme know if you run into any issues with it.
blog comments powered by Disqus

More

Read more posts by Michael

About the Author

A software developer and network engineer for over 25 years. Currently developing Microsoft Windows desktop applications with Delphi and web services with Ruby, Ruby on Rails, Ramaze and Javascript. Web services are hosted on CentOS and Ubuntu servers under either Xen or VMWare powered via Apache, passenger, mysql and postgresql.