Guide to Rails Metal 310

Posted by mikong on February 03, 2009

  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.

For this guide, we’re writing a Widget Refresher Metal app. Supposedly, the widget page of our Rails application gets called too much, and so we want to take advantage of Metal. Under our project’s app/metal folder, we create refresher.rb:

  class Refresher < Rails::Rack::Metal
    def self.call(env)
      refresher = RefresherApp.new
      refresher.call(env)
    end
  end

  class RefresherApp
    def call(env)
      # refresh widget path: /widgets/:id/refresh
      if env["PATH_INFO"] =~ /^\/widgets\/(\d+)\/refresh/
        widget_id = $1
        prepare(env, widget_id)
        refresh
      else
        [404, { "Content-Type" => "text/html" }, "Not Found"]
      end
    end

    # to setup the environment
    def prepare(env, widget_id)
      ...
    end

    # the heart of our Metal app
    def refresh
      ...
    end
  end

I like to create a separate class RefresherApp instead of just writing all of it inside the Refresher class (the one that extends from Rails::Rack::Metal). When your Metal app becomes more than just a trivial hello world app, you’ll be needing a bunch of methods calling each other. Since the call method in the Metal app is a class method, putting all the code in one class will require all these methods to be class methods as well. And I think that looks ugly. Feel free to stick it all in one class if you want. If you do, you can change the context to self so you don’t have to keep on defining each method as self.method:

  class Refresher < Rails::Rack::Metal

    # the methods in here are class methods
    class << self
      def call(env)
        ...
      end

      def method
        ...
      end
    end

  end

For the rest of the guide, we’re using my approach. Also, note that when developing a Metal app, you need to keep on restarting your server for your code changes to take effect.

Request and Session

To access the request and the parameters in it, you can use this code:

request = Rack::Request.new(env)
params = request.params
params['mykey'] # String keys, so not params[:mykey]

As you can see, the keys will be of class String, not Symbol. Now for the session, you can get it from the environment:

session = env['rack.session']

We can move all these code into our prepare method. In addition, we can set the params[:id] (using a Symbol if you want), so that in our main refresh method, it would be like in a Rails controller. With the session, we can get the current user. We can also define other methods to make things more like writing code for a Rails controller. This is how it looks like:

  attr_reader :request, :session, :current_user

  def params
    @request.params
  end

  def logged_in?
    !!current_user
  end

  def prepare(env, widget_id)
    @request = Rack::Request.new(env)
    params[:id] = widget_id
    @session = env["rack.session"]
    @current_user = session[:user_id] ? User.find(session[:user_id]) : false
  end

With these out of the way, we go into writing the code for the main method called refresh.

refresh and ActiveRecord

ActiveRecord works out of the box, no setup needed. Cool! Let’s say we just need to return the status of widget to the client side:

  def refresh
    @widget = Widget.find(params[:id])

    return [200, { "Content-Type" => "text/html" }, @widget.status]
  end

We can also send javascript code, or other content types back to our client. Just make sure to set your content type properly. Let’s also add some simple checking if the user is logged in:

  def refresh
    @widget = Widget.find(params[:id])

    if logged_in?
      return [200, { "Content-Type" => "text/javascript" }, "Element.update('status', '#{@widget.status}');"]
    else
      return [200, { "Content-Type" => "text/javascript" }, "Element.update('message', 'Must be logged in for widget status to refresh');"]
    end
  end

When returning more complex javascript however, it’s probably better to escape the newlines and the quotes or we’ll get parsing errors on the browser side. Rails provides a helper method called escape_javascript, but a Metal app doesn’t have access to helpers by default. So…

View Helpers

To use helpers in your Metal app, just include the modules you need:

  include ActionView::Helpers::JavascriptHelper # so escape_javascript works
  include WidgetsHelper # for example

I prefer to avoid including too much of these helpers though.

Request Forgery Protection

If the request is not a GET request, we may need to verify the authenticity token. Here’s one way to do it:

  def refresh
    # before everything else
    return redirect_to_widgets_response unless verified_request?

    # everything else
    ...
  end

  def redirect_to_widgets_response
    return [302, { "Content-Type" => "text/html", "Location" => "/widgets" },
      "<html><body><a href=\"/widgets\">Redirecting...</a></body></html>"]
  end

  # Based on Rails method of the same name but simplified, i.e. no need to check if:
  #   - protection is disabled
  #   - request method is :post
  #   - format is verifiable
  def verified_request?
    form_authenticity_token == params['authenticity_token']
  end

  def form_authenticity_token
    session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
  end

More Challenges

There are other challenges you may encounter in writing your Rails Metal app. I have tried rendering a partial by directly using ERB but it’s too ugly to show here. And I’ve also struggled with performance. Not all business logic can simply be translated to a Metal app to be fast. It is recommended for very simple things only, or it may not be worth it. Anyway, I hope this guide clears up a few things. Also, if you have better ways of doing any of the above, feel free to post in the comments. Thanks!

Basic User Signup with MerbAuth 341

Posted by mikong on October 27, 2008

It’s amazing how fast Merb has changed since I’ve dabbled with it early last month. I used the merb-auth plugin then and it was pretty ok, being familiar with the restful authentication plugin for Rails. But the merb-auth plugin is now obsolete, after only being introduced last June.

Enter MerbAuth

Daniel Neighman (aka hassox) gave a talk during MerbCamp on MerbAuth and MerbSlices and you can download his slides from his github account. There’s also a recipe in the Merb Wiki cookbook for an Authenticated Hello World using MerbAuth, so be sure to check those out before following the tutorial below.

MerbAuth Setup

As detailed in the Authenticated Hello World tutorial, MerbAuth is already in your Merb stack and you can use it right after:

  1. generating your merb app
  2. setting up your database, and
  3. creating a hello world controller

So you just add the authentication in your router or your controller and you’re good to go.

Basic User Signup

This tutorial will show how to add validations to your User model, prepare your Signup page, and setup your Users controller. There are comments along the way that explain basic Merb stuff to someone with a Rails background. It assumes your Merb app uses Datamapper for its ORM and ERb for its templating engine, the defaults when generating a new Merb app.

Validations

It may be a bit weird that the User model is almost empty, looking like this:

class User
  include DataMapper::Resource

  property :id,     Serial
  property :login, String
end

You don’t see it there, but MerbAuth already has your back for validating the presence of password, and making sure it’s confirmed with the password_confirmation field. But you probably want to add that the login is unique, and perhaps validate the length of your login and password.

class User
  include DataMapper::Resource

  property :id,     Serial
  property :login, String

  validates_length      :login,        :within => 3..40
  validates_is_unique :login
  validates_length      :password, :within => 4..40, :if => :password_required?
end

Those are all pretty basic. But it’s good to note that there’s a :password_required? inside MerbAuth that you can use here, just as you were able to in the old days of merb-auth plugin. Add other fields such as created_at, updated_at or email and add more validations as you see fit.

Signup page

Create a new.html.erb file under app/views/users:

<%= error_messages_for @user %>
<%= form_for @user, :action => url(:users) do %>
  <p>
    <%= text_field :login, :label => "Login" %>
  </p>
  <p>
    <%= password_field :password, :label => "Password" %>
  </p>
  <p>
    <%= password_field :password_confirmation, :label => "Password Confirmation" %>
  </p>
  <p>
    <%= submit "Sign up" %>
  </p>
<% end =%>

It’s very similar to Rails but there are subtle things to note here. First, we use ‘form_for’ because we have a user resource for the form fields, just like in Rails. If it were a custom form that’s not based off of a resource, we’d use ‘form’ (Merb’s counterpart to Rails’ ‘form_tag’). For Merb, it’s important that you don’t miss the = in the ‘<%= form_for … end =%>’ or you would only see a blank Signup page.

Second, we have the field helpers. We had text_control, password_control and submit_button in the old Merb but now, we have text_field, password_field and submit and I think the view looks better. These same helpers are used even if you’re using ‘form’ instead of ‘form_for’, unlike having to use a different set of *_tag helpers in Rails. Note also the :label option of the field helper.

Users controller

Run ‘merb-gen controller users’ or create a users.rb file under app/controllers:

class Users < Application

  def index
    render
  end

  def new
    only_provides :html
    @user = User.new
    display @user
  end

  def create(user)
    session.abandon!
    @user = User.new(user)
    if @user.save
      redirect "/", :message => {:notice => "Signup complete"}
    else
      message[:error] = "Signup failed"
      render :new
    end
  end

end

A Merb controller differs with a Rails one in a lot of ways and I’ll just comment on a few. Merb has render and display methods. Then, there’s the convenience of specifying a parameter to be stored in a variable in your action like in the create action above. In that case, the params[:user] is automatically stored in a local variable named user.

In Merb, your controller actions need to explicitly return something. If you remove ‘render’ in the index action above, it’ll be like returning nil as your response. Return a string, like “hello world” in the Authenticated Hello World example, and it sends that string as response to the client. If you need to return an XML representation of your object, it’s as easy as having the action return @object.to_xml.

Last thing to note, we call session.abandon! in our create action to clear the session, practically logging out the user. This method is provided by MerbAuth.

Routing

You may add the following to your router.rb file:

  resources :users
  match('/signup').to(:controller => 'users', :action => 'new')

That’s it!

I hope this makes a good companion to the Authenticated Hello World recipe, and does it’s job of showing what you can do next with MerbAuth while introducing some of the basic concepts in Merb. There’s more to MerbAuth than what we’ve covered here. You might want to check its RDoc. There’s even the concept of MerbAuth Strategy (see hassox’s MerbAuth slides) I haven’t explored yet.

Programming and My Other Passion 11

Posted by mikong on July 24, 2008

I sometimes wanted to write an article about Go (board game) in this development blog, but I could never justify it. But now that a couple of Ruby/Rails blogs posted articles this year relating programming to Go, I finally have an excuse. :)

The first article is from the O’Reilly Ruby blog entitled “Ruby Conferences vs. Go Tournaments”. The other one is from the Rails Spikes blog, “Why programmers should play Go”, which Fabio Akita even translated to Portuguese (with additional notes) in his Akita on Rails blog. Check them out!

I was pleasantly surprised to find that these developers also have passions for both Go and programming and even went so far as comparing them. Previously, the only way I could think of linking the two was to create a Go program using Ruby. But now that I think about it, it seems like they’re connected on a deeper level.

Go and programming are my passions that take up most of my time. It has been a real struggle to balance the two. Every time I program too much, I would start to miss Go and do my best to find time for it. At times it’s the other way around. And then I just realized, I started to learn both Ruby and Go at about the same time (end of December 2006). I even joined the Philippine Ruby Users Group (PhRUG) and started the Philippine Go Association mailing list at about those times too. A coincidence? I THINK NOT!

If you don’t know Go, I encourage you to read about it. If you’re a fellow PhRUG member who knows Go and wants to play a game with me, or wants to learn it, you can send me an email through the group. Or just join our Go mailing list.

Grails and Rails 250

Posted by mikong on February 12, 2008

I didn’t like the idea of checking out Grails. I mean if I’m already a Rails developer, why bother checking a copycat. That’s why I’m surprised I found things I liked about it. But will I leave Ruby on Rails for it? This article is about my first impressions of Grails after reading the book Getting Started with Grails, sections of their online documentation and some Grails-related articles.

Some Good Stuff

After you run ‘grails run-app’ (the equivalent of ’script/server’ in Rails) you can access your application with the URL http://localhost:8080/app_name and get a ‘Welcome to Grails’ page. It’s a minor thing but I like having the application name in there. When you type your application URL by hand in the address bar and you’re shown the cached URLs, it looks more organized. Multiple Grails applications can run together without having to reconfigure URLs. The Welcome page also includes links to the index page of each of your controller so that’s another nice addition. (Note: The URLs to the other pages of a Grails application is accessed by appending controller/action/id to the URL, just like Rails.)

Grails ships with HSQLDB which makes playing with simple applications really easy. You can create your app at the start without thinking about the database. Of course, your data won’t persist this way because HSQLDB stores your data in memory, but I don’t really care about that when I’m just playing around. In Rails 2.0.2, the default DB was changed to SQLite3 so you don’t have to setup your database but you need SQLite3. In Grail’s HSQLDB, you only need Java which you should already have if you’re using Grails.

In Grails, models are ‘domain classes’. Grails domain classes remind me of DataMapper, the Ruby ORM. You list down the properties of the domain in the class, and the framework generates the table with these columns in the database. So instead of adding a column through a migration, just add a property in your domain class. You won’t need an Annotate Models plugin here.

And there are other nice things in Grails. Because Grails is on top of Java, you have i18n support out of the box. The Grails tag library is also a clean approach to views.

Some Bad Stuff

I have a few issues with Grails defaults. The first problem I had with Grails is that the generated DB columns are required or cannot be NULL. You need to declare in your domain class the columns that are optional. I don’t really get this because in most of the applications I’ve worked with, there are more optional columns than required ones. Also, I’m the type of Rails developer that avoids adding constraints in the DB unless I have to. If my application is the only thing that accesses my database, then I’ll put my constraints in one place, the application-side.

One of the many little things I like about Rails is if you have created_at and updated_at columns, they are automatically set when you save a record. You also have the timestamps method added in your generated model migration by default that adds these 2 columns. In Grails, you need to specify a createdAt property in your domain class, and set it manually to new Date().

In contrast to Rails, Grails controllers do not extend an application controller by default. It’s a minor thing but I would probably need to extend it manually for every Grails application I write, hypothetically speaking.

In Grails, you’re not supposed to need to restart your server when you make changes. But this is not entirely true. When you add static constraints to your domain classes, add new messages, or a new Java class, you still need to restart. For Java developers, it’s better than having to build and deploy a WAR file every time, but it’s still a bit irritating to me.

You can mix Java and Groovy in your Grails application. This can be good in a lot of ways but I think it can also be bad. Java developers working on a Grails application may be tempted to use their old, inefficient ways instead of taking the leap to Groovy. Or when Groovy doesn’t support a Java construct a Java developer is used to, you end up with verbose code, like the search implementation in the Getting Started with Grails book (see Working with Java Classes starting at page 63). This was particularly disturbing and made me think: if Java always has Groovy’s back, Groovy might depend on Java too much.

It’s Really the Syntax

My issues with Grails so far are minor but the thing for me is: Ruby/Rails syntax is just more beautiful than Java/Groovy/Grails syntax.

Mapping a has_many association in Rails:

  has_many :registrations

In Grails:

  static hasMany = [registrations:Registration]

Adding a before filter in your controller in Rails:

  before_filter :auth, :except => 'search'

In Grails:

  def beforeInterceptor = [action:this.&auth, except:['search']]

The end of Rails?

I won’t be surprised if Grails becomes more popular than Rails but only because Java is currently the most popular language in the industry (based on TIOBE). Grails is for Java developers who don’t want to leave their comfort zone. It offers something a lot better than the current Java web frameworks and that’s a good thing. But I like Rails better; I might only consider Grails if I have to integrate with Java. And I prefer Ruby over Groovy. Groovy is the dynamic language that looks like Java so that Java developers have an easier transition. That has a cost though, and one may be that it will never be as beautiful as Ruby.

Learning Ruby 1.9 7

Posted by mikong on December 25, 2007

I’m not going to list down “improve Ruby skills” on my New Year’s resolution. With the newly released Ruby 1.9.0 (a development release) and beta book Programming Ruby 3 by Dave Thomas (or simply Pickaxe 3), what better time to dig deeper into Ruby than now?

When I setup Rails on my mac a few months back (before Leopard and Rails 2.0), I followed Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X by Hivelogic. Following the Ruby part of that but updated for Ruby 1.9:

  cd /usr/local
  sudo curl -O  ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.0-0.tar.gz
  sudo tar xzvf ruby-1.9.0-0.tar.gz
  cd ruby-1.9.0-0
  sudo ./configure --prefix=/usr/local/ruby-1.9.0 --enable-pthread --with-readline-dir=/usr/local
  sudo make
  sudo make install

I didn’t have to run ‘make install-doc’ because ‘make install’ already installed the documentation. Since I haven’t upgraded to Leopard yet, this has only been verified on Tiger. Running ‘/usr/local/ruby-1.9.0/bin/ruby -v’, I got

  ruby 1.9.0 (2007-12-25 revision 14709) [i686-darwin8.11.1]

Cool! And I just bought Pickaxe 3 (right after installing). Looking for the first 1.9 feature I can find in the book… a new hash syntax:

  $ /usr/local/ruby-1.9.0/bin/irb
  irb(main):001:0> inst_section = { cello: 'string', clarinet: 'woodwind' }
  => {:cello=>"string", :clarinet=>"woodwind"}
  irb(main):002:0> inst_section[:clarinet]
  => "woodwind"

It works! And let me just add that new hash syntax looks gorgeous. Now I have to end this article and try a 1.9 feature beyond mere syntax updates. Chapter 11: Fibers, Threads, and Processes looks like a good place to start… :)

Update 12/26/2007: I initially installed Ruby 1.9 on /usr/local. It installed rubygems 1.0.1 with it and messed up my gem installation for 1.8.6. I had to reinstall 1.8.6, and then reinstall ruby 1.9 in an isolated directory, /usr/local/ruby-1.9.0. I updated the article to use this directory. For now, I only use 1.9 to try the new features. If you need to work with multiple versions of Ruby, you might want to check out Dan Manges’ article.

My Git notes for Rails 1

Posted by mikong on December 17, 2007

From Toolman Tim’s blog entry Setting up a new Rails app with Git (with a few changes, and summarized for personal reference).

$ git init
$ mate .gitignore

Add in .gitignore:

log/*.log
tmp/**/*
.DS_Store
doc/api
doc/app
config/database.yml
db/schema.rb

Back to the command line:

$ cp config/database.yml config/database.yml.example
$ touch log/.gitignore
$ touch tmp/.gitignore
$ git add .
$ git commit -m "Initial commit"

Additional Notes:

  find . \( -type d -empty \) -and \( -not -regex ./\.git.* \) -exec touch {}/.gitignore \;

Blogging From TextMate, and RubyConf 2007 videos 254

Posted by mikong on December 13, 2007

This is a test post following an old TextMate screencast demonstrating the blogging bundle.

Continue reading…

PHRUG’s 2nd Rails Coding Session 2

Posted by mikong on December 07, 2007

Last Wednesday, I attended the 2nd Rails Coding Session of the Philippine Ruby Users Group (PHRUG). The small, informal gathering was planned for writing Rails apps with plugins like acts_as_solr, memcached, etc. None of us wrote a single line of code. Instead, we discussed several Rails and Ruby topics and gathered ideas for future Rails events.

Some of the topics discussed were:

The future Rails events planned are coding sessions (hopefully with actual coding involved), monthly meetups (with the next meetup probably in January and to be held at either the Ateneo de Manila University campus or Stratpoint Technologies office), and possibly a Philippine Rails Conference. Some notable issues covered were the challenges of organizing a large conference (including problems involved with having closed source companies as sponsors), and  problems with matching the level of explanation in your presentations with the knowledge of your audience.

The Rails community in the Philippines is only starting to grow. But I’m glad that the local Rails events are increasing in both frequency and number of participants. Previous Rails events I’ve attended are the First PHRUG Meetup last January, Rails Happy Hour last September, Rails Talk with the presentation by Guy Naor last October, and most recently this “coding session” (I missed the 1st Rails Coding Session 2 weeks ago).

Before I end this post, I’d like to thank Rad and the Development Executive Group for accommodating us for the session.

An RSpec example for code you should not write 1

Posted by mikong on November 16, 2007

I have very recently started practicing Behaviour-Driven Development (BDD) using RSpec on Rails. RSpec is a framework “to describe the behaviour of Ruby code with readable, executable examples that guide you in the design process and serve well as both documentation and tests” (definition taken from the RSpec project home page). A programmer practicing BDD goes through cycles of describing a behaviour, writing the test for it, before finally writing the code to implement it. If you need more introduction to BDD and using RSpec, head over to Rails Envy for a good presentation on this.

In that presentation, Gregg Pollack mentioned that it’s good to have tests for every line of code. I’ve been thinking about that and while writing a particular RSpec example, I realized I just wrote something that tests… well… a code I should not write. Please consider this case I’ll describe.

Let’s say there’s a time-box called Foobar where a team needs to work on a list of tasks. Since it’s a definite period of time, the team has a limited number of manhours. The tasks defined in the list have estimated hours needed to finish it. That means tasks can only fit in the Foobar if their total estimated hours are within the limited number of manhours, right? Initially, this was thought to be the case. But it was later specified that the tasks’ estimated hours are only estimates, and so a requirement was added that the Foobar should be allowed to have a list of tasks where the total estimated hours exceed the total manhours available.

The RSpec example code could look something like this:

describe Foobar do
  fixtures :foobars
  ...
  # Testing for code you should not write
  it "should be allowed to have tasks where the total estimated hours exceed the Foobar period's total manhours" do
    foobars(:thirty_day_foobar).tasks<<(Task.new(:desc => "Task 1", :estimated_hours => 10))
    # This 2nd task has an estimate of 1 million hours.
    # You'd need about 1400 people working 24 hours-a-day for 30 days to do this.
    foobars(:thirty_day_foobar).tasks<<(Task.new(:desc => "Task 2", :estimated_hours => 1000000))
    foobars(:thirty_day_foobar).save.should be_true
  end
end

OK, I know I need to work on my RSpec writing skills but I hope you get the point. The behaviour example above doesn’t need any implementation code to work. It just works, and it prevents the web developer from writing validation code that will prohibit tasks from being added to the Foobar. It looks fine to me, but it would be good to get some feedback.