Pastie Implementation with Rails Metal

Posted in Ruby on Rails by Srinivas Reddy on June 20, 2009

Rails Metal:
Rails Metal is a way to cut out the fat of the MVC request processing stack, to get the quickest path to your application logic. This is especially useful when you have a single action that you need to run as quickly as possible and can afford to throw away all the support Rails normally provides in exchange for a very fast response time.

Though its really easy for any Rails developer to start building metal applications, it is a very sharp tool. Rails developers should still continue to use Rails as they normally do, but when they are sure that a specific action requires extra performance, the tools are available.

Writing a Rails Metal app can make you realize just how spoiled we’ve become with all the convenience that comes with Rails. Without the controller and view helpers, it can become a painful experience. Here’s a guide to help make it a better experience.

rails 2.3
Syntax converter: Syntax is, first and foremost, a lexical analysis framework. It supports pluggable syntax modules, and comes with modules for Ruby, XML, and YAML
Install using the command: sudo gem install syntax
syntax more…

create rails app:

srinivas@srinivas:~/work# rails pastie –database=mysql

move to app directory:

srinivas@srinivas:~/work# cd pastie


srinivas@srinivas:~/work/pastie# ruby script/generate model snippet code:text

run migration:

srinivas@srinivas:~/work/pastie# rake db:migrate

create metal:

srinivas@srinivas:~/work/pastie# ruby script/generate metal pastie

Lets edit the metal file pastie.rb which is created in app/metal directory to the code snipped for quick start working metal.

# Allow the metal piece to run in isolation
require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails)

require 'syntax/convertors/html'      

class Pastie
    if env["PATH_INFO"] =~ /^\/\d+$/

      @snippet = Snippet.find(env["PATH_INFO"].gsub!(/\D/,'').to_i)

      convertor = Syntax::Convertors::HTML.for_syntax 'ruby'

      html = convertor.convert(@snippet.code)
      [200, {"Content-Type" => "text/html"}, [html]]

    elsif env["PATH_INFO"] =~ /^\/new$/
      new_form_html = "<html><body><h1> Paste Your Code </h1>

 <form action='/create' class='new_snippet' id='new_snippet' method='post'>
 <textarea cols='40' id='snippet_code' name='snippet' rows='20'></textarea>
 <input name='commit' type='submit' value='Create' />
      [200, {"Content-Type" => "text/html"}, [new_form_html]]

    elsif env["PATH_INFO"] =~ /^\/create$/
      request =

        params = request.params['snippet']

        snippet =

        response =
        response['Content-Type'] = 'text/html'

        response['Location'] =
        response.status = 301

      [404, {"Content-Type" => "text/html"}, ["Not Found"]]

    <span class="comment" style="color:#919191;"# Release the connections back to the pool.

  • env["PATH_INFO"] =~ /^\/new$/ check for the new pastie path (http://localhost/new) and renders the form to ruby code.
  • env["PATH_INFO"] =~ /^\/create$/ checks the request for save the pastie (http://localhost/create) and saves into the database. which creates a unique id for the current entered pastie
  • env["PATH_INFO"] =~ /^\/\d+$/ checks the particular pastie to display (http://localhost/1 #unique digit), it just queries the snippets from the database using the unique id given in the path info
    @snippet = Snippet.find(env["PATH_INFO"].gsub!(/\D/,'').to_i)
    parse the output to the convertor object more...

Rack::Response provides a convenient interface to create a Rack response, so write the response body with the pastie that returned by the syntax converter and finish the response. This will return the status, headers and response body(html)

Rails doesn’t take care of certain things in Rails Metal pieces, including the releasing of connections back to the database connection pool.
Moral of the story: Don’t forget to release your database connections if you’re using ActiveRecord in your Rails Metal. Or even better, don’t use ActiveRecord in Rails Metal – you’re aiming for raw speed anyway right?
Rails Metal piece to always ensure it clears any active database connections with ActiveRecord::Base.clear_active_connections!
Which was actually found in rails bug tracker

Please find the similar but well refactored implementation of metal here by Gautam Chekuri, and it shows the benchmark difference between wtih/without ActiveRecord.