Rendering templates in Rails Metal

One of the things that has caught my interest lately is Rack. After reading about it a bunch I was looking for a way to start integrating it into my projects somehow. Adam Wiggins of Heroku, had an interesting presentation that called Rails Metal the “a gateway to the world of Rack.” Its a good description, and one that gave me a starting place for using Rack in my project.

If you run the “script/generate metal nameofMetalApp” command, Rails will generate the code for a small Rack app and dump it in the app directory of your project in a folder called “metal”. Inside that app, there are no Rails helpers, no convenience methods, no redirects or renders. You really are in a new world.

The reason for that is that Rails won’t have been loaded when the a request hits this little app. Its only if the apps in the metal folder all return 404 that Rails gets loaded at all.
What is gained here is speed. If a couple lines of code is sufficient to handle the request, why load an entire framework? For simple actions that happen a lot, it can make a big difference. The first thing I wanted to know was how to render HAML or ERB pages in my Metal apps.

Since that is probably pretty common I thought I would post it up here. Its not complicated but it will save some searching. I decided I would create a Metal end point that would serve up a static “about” page. There are many useful things to do with Metal, and while an “about” page might not be one of them, its a good place to start:

# Allow the metal piece to run in isolation
require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails)
#added HAML
require 'haml'
class AboutApp
  def self.call(env)
    if env["PATH_INFO"] =~ /^\/about/
      @time = Time.now
      #Render a HAML template using the HAML engine
      #http://haml-lang.com/docs/yardoc/Haml/Engine.html
      template = File.read(File.join("app","views", "static", "about.html.haml"))
      haml_engine = Haml::Engine.new(template)
      output = haml_engine.render(binding)
      #Alternately you can render an ERB template
      #http://ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
      #template = File.read(File.join("app", "views", "static", "about.html.erb"))
      #output = ERB.new(template).result(binding)
      [200, {"Content-Type" => "text/html"}, ["#{output}"]]
    else
      [404, {"Content-Type" => "text/html"}, ["Not Found"]]
    end
  end
end

Notice that I am creating an instance variable @time which is available in the templates because I am passing in binding objects to the renderer for both HAML and ERB.
And a basic template so we can see that its working (excuse the lack of spacing, wordpress is messing it up):

!!!
%html
  %body
    %h1 The time is
    %p
      =@time

Then fire up your server and request “/about”. That’s it. The thing to remember is that these Metal apps are real Rack apps. While most of them will be pretty basic, they don’t have to be. They just have to conform to the Rack spec. I have been curious about Sinatra for a while now and this seemed like a good time to try it out and see if I could use it instead of Metal. I wrote a quick little Sinatra app and dropped it into the metal folder, requested “/test” and there it was. (Again, excuse the lack of spacing)

require 'rubygems'
require 'sinatra'
require 'haml'
class TestApp < Sinatra::Application
  get '/test' do
    output =<<-EOHAML
    !!!
    %html
      %body
        %h1
          Hello from Sinatra!
    EOHAML
    haml output
  end
end

While the purpose of all this is performance, it also seems that this is a fairly nice way to add other apps to your existing one. Say, if I wanted to run a basic CMS alongside one of my Rails apps for marketing purposes. What’s extra cool is that using a Rack based authentication middleware like Warden would mean that both apps would share an authentication mechanism. There are a lot of possibilities to explore!

Advertisements

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