CNU CODE

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.

Requirement:
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…

Start:
create rails app:

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

move to app directory:

srinivas@srinivas:~/work# cd pastie

model:

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
  def self.call(env)
    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' />
 </form></html></body>"
      [200, {"Content-Type" => "text/html"}, [new_form_html]]

    elsif env["PATH_INFO"] =~ /^\/create$/
      request = Rack::Request.new(env)

      if request.post?
        params = request.params['snippet']

        snippet = Snippet.new(params)
        snippet.save

        response = Rack::Response.new()
        response['Content-Type'] = 'text/html'

        response['Location'] = snippet.id.to_s
        response.status = 301

        response.finish
      end
    else
      [404, {"Content-Type" => "text/html"}, ["Not Found"]]

    end
  ensure
    <span class="comment" style="color:#919191;"# Release the connections back to the pool.
    ActiveRecord::Base.clear_active_connections!
  end

end
  • 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)

Imp:
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.

Thanks
Srinivas

Advertisements

2 Responses

Subscribe to comments with RSS.

  1. gautam said, on June 21, 2009 at 12:31 pm

    that was a inspiring implementation … :). I tried something similar that I have described on my blog: http://www.chartstreet.in/blog/16

  2. Metal Session « CNU CODE said, on July 25, 2009 at 11:50 am

    […] } In my previous post there is a simple metal application, implementation fast metal paste kind of […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: