Announcing ActionRails 11

Posted by pratik
on Thursday, April 23

I’m very happy to announce ActionRails – a new consulting firm jointly owned by Koz (Rails core, therailsway.com author), Mike Gunderloy (Rails documentation/activist team) and myself.

ActionRails is not trying to be yet another consultancy that develops applications from start to finish (though we can talk to you individually about such projects). Rather, we have a distinct set of services, designed to help customers complete successful Rails deployments and helping existing teams improve their Rails skills. Our menu currently offers:

  • Application Evaluation
  • Weekly Code Reviews
  • Developer Hotline

ActionRails has already been working for a few select clients, helping them out with reviewing code, offering course corrections, and evaluating application architecture (among other things). You can hop over to our site for more information, or just drop us a line.

Default Scopes and Inheritance to the rescue 11

Posted by pratik
on Tuesday, March 24

On my one of the current projects, there are two primary models each with a flag called approved. 99% of the front end part deals with only approved items. Unapproved items are usually only in the admin panel side of the story. So I started with using a named_scope called approved:

1
2
3
4
5
6
class Item < ActiveRecord::Base
  has_many :tags

  default_scope :order => 'items.name ASC'
  named_scope :approved, :conditions => { :published => true }
end

And now I’d have to use Item.approved. everywhere in my application. But that became a bit too cumbersome sooner than later. Playing around with this a bit, I came up with the solution using default_scope and the good ol’ inheritance:

1
2
3
4
5
6
7
8
9
10
11
12
class Item < ActiveRecord::Base
  has_many :tags

  default_scope :order => 'items.name ASC'
end

class PublishedItem < Item
  set_table_name 'items'
  set_inheritance_column nil # hax?

  default_scope :conditions => { :published => true }, :order => 'items.name ASC'
end

Checking this on console :

>> p = PublishedItem.first
  SELECT * FROM `items` WHERE (`items`.`published` = 1) ORDER BY items.name ASC LIMIT 1

>> i = Item.first
  SELECT * FROM `items` ORDER BY items.name ASC LIMIT 1

Seems to work just fine.

You could do it the other way around too:

1
2
3
4
5
6
7
8
9
10
11
12
13
class RawItem < ActiveRecord::Base
  set_table_name 'items'
  has_many :tags

  default_scope :order => 'items.name ASC'
end

class Item < RawItem
  set_table_name 'items'
  set_inheritance_column nil # hax?

  default_scope :conditions => { :published => true }, :order => 'items.name ASC'
end

Whichever one works for you.

Please note that the above code is NOT using STI. It’s using set_inheritance_column nil workaround to bypass the Active Record STI stuff and rely just on the ruby inheritance.

My Rails guides 3

Posted by pratik
on Wednesday, March 18

Instead of blogging some of the articles, I decided to write those as Rails guides. So go ahead and check them out !

I also wrote a lot of the Active Record Query Interface guide. Of course my guides aren’t really eligible for the guides hackfest prizes. But hey, you could still win them by writing a new guide !

assert_* and assert_not_* 4

Posted by pratik
on Tuesday, March 17

Not sure I like this or not, but I’m gonna give it a shot in the “real world” nevertheless.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module AssertionExtensions
  def method_missing(method_id, *arguments, &block)
    return super unless method_id.to_s =~ /^assert_(not_)?(.*)$/
 
    method = "#{$2}?"
    object = arguments.first
 
    if $1
      arguments.each do |object|
        assert ! object.send(method), "#{method} is not false for #{object}"
      end
    else
      arguments.each do |object|
        assert object.send(method), "#{method} is not true for #{object}"
      end
    end
  end
end
 
class ActiveSupport::TestCase
  include AssertionExtensions
end

Now using this in your tests:

1
2
3
4
5
6
7
8

def test_is_admin
  # [people(:admin), people(:superuser)].each {|p| assert p.admin?}
  assert_admin people(:admin), people(:superuser)

  # assert ! people(:foo).admin?
  assert_not_admin people(:foo)
end

Make Test::Unit display errors earlier 4

Posted by pratik
on Saturday, March 14

Just a monkey patch to make Test::Unit display errors as soon as they happen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require 'test/unit'
require 'test/unit/ui/console/testrunner'

class Test::Unit::UI::Console::TestRunner
  def add_fault(fault)
    hax_output(fault)
    @faults << fault
    output_single(fault.single_character_display, 1)
    @already_outputted = true
  end

  def hax_output(fault)
    @io.puts("\n")
    output_single(fault.short_display, 1) # fault.long_display for the full trace
    @io.puts("\n")
  end
end

Useful when your tests take too long to run.

The Evil calls back 0

Posted by pratik
on Thursday, January 15

Happy new year!

Just an update on the two middlewares I contributed to rack-contrib. In case you don’t already know what is rack-contrib, it’s a project started by Ryan Tomayko as a playground for experimental Rack middlewares from the ruby community. There are 15 middlewares there already, so do check it out!

Rack::Evil

The name says it all. It’s pure evil, as it enables the rack application to return the response from any place during while it’s serving the request by doing throw :response, [status, header, body].

Example:

1
2
3
4
5
6
7
8
9
10
app = lambda do |env|
  template = <<-TEMPLATE
  Hello Template
  <%= throw :response, [404, {'Content-Type' => 'text/html'}, 'From Template'] %>
  Never
  TEMPLATE
  result = ERB.new(template).result(binding)

  [200, {'Content-Type' => 'text/plain'}, "Ran the template"]
end

And the response reaching the client will not be “Ran the template” with 200 status. But it’ll be “From Template” with 404 status!

Rack::Callbacks

Now that more people are getting on board with the concept of middlewares, people have started using middlewares for pure before/after filter kind of things. And I think don’t think that’s the best way moving forward. That’s the problem Rack::Callbacks tries to alleviate.

Rack::Callbacks lets you wrap your rack application with a series of before and after callbacks.

Example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TimeZone
  def initialize(default)
    @default = default
  end

  def call(env)
    env['rack.timezone'] = find_timezone(env) || @default
  end
end

class CompressBody
  def call(response)
    status, headers, body = response

    compressed_body = zip_body(body)
    [status, headers, compressed_body]
  end
end

app = Rack::Callbacks.new do
  before TimeZone, "default"

  run YourPrimaryRackApp.new

  after CompressBody
end

The flow of execution is very apparent here. All the before callbacks are run first, then the actual application and after callbacks at last.

before Callback, arg1, arg2….argx

before() takes Callback class as the first argument. Optional arguments are passed to Callback#initialize. This is very similar to the regular rack middlewares. However before callbacks are quite different from middlewares.

Callback#call accepts a single argument : env. However, the return value of Callback#call is simply discarded.

run Application

Runs the primary rack application.

after Callback, arg1, arg2….argx

after() takes Callback class as the first argument. Optional arguments are passed to Callback#initialize. Just like before() and middlewares. However, after callbacks are substantially different from before callbacks and middlewares:

Callback#call accepts a single argument : response, which is the rack response returned by the application or other after filters. Callback#call also must return a valid rack response. Return value of Callback#call is supplied to the next after filters in the stack, and the final after filter returns the response to the client.

Rails templates 54

Posted by pratik
on Thursday, December 04

So now that Edge Rails got templates ( Thanks to Jeremy ) I just wanted to give a top level overview.

Templates are simple ruby files containing DSL for adding plugins/gems/initializers etc. to your freshly created Rails project. To apply the template, you need to provide rails generator with location of the template you wish to apply, using -m option :


rails blog -m ~/template.rb

Thanks to the magic of open-uri, the template location can be a URL too :


rails blog -m http://gist.github.com/31208.txt

You can even apply templates to your existing Rails application using rails:template rake task and supplying LOCATION environment variable :


rake rails:template LOCATION=~/template.rb

A very simple template would look like :

1
2
3
4
5
6
7
8
9
# template.rb
run "rm public/index.html"
generate(:scaffold, "person name:string")
route "map.root :controller => 'people'"
rake("db:migrate")

git :init
git :add => "."
git :commit => "-a -m 'Initial commit'"

That’s very self explanatory. Here are the key methods for the template DSL :

gem(name, options = {})

Adds a config.gem entry for the supplied gem to generated application’s config/environment.rb

So if your application depends on bj and hpricot :

1
2
gem "bj"
gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"

Please note that this will NOT install the gems for you. So you may want to run rake gems:install:


rake "gems:install"

And let Rails take care of installing the required gems if they’re not already installed.

plugin(name, options = {})

Installs a plugin to the generated application.

Plugin can be installed from Git :


plugin 'authentication', :git => 'git://github.com/foor/bar.git'

You can even install plugins as git submodules :


plugin 'authentication', :git => 'git://github.com/foor/bar.git', :submodule => true

Please note that you need to git :init before you can install a plugin as a submodule

Or use plain old SVN :


plugin 'wtfsvn' :svn => 'svn://crap.com/wtf/trunk'

initializer(filename, data = nil, &block)

Adds an initializer to the generated application’s config/initializers directory.

So personally, I like using Object#not_nil? and Object#not_blank? :

1
2
3
4
5
6
7
8
9
10
11
initializer 'bloatlol.rb', <<-CODE
class Object
  def not_nil?
    !nil?
  end
  
  def not_blank?
    !blank?
  end
end
CODE

Similarly lib() creates a file in lib/ directory and vendor() creates a file in vendor/ directory. There is also file(), which accepts a relative path from RAILS_ROOT and creates all the directories/file needed :

1
2
3
4
file 'app/components/foo.rb', <<-CODE
class Foo
end
CODE

That’ll create app/components directory and put foo.rb in there.

rakefile(filename, data = nil, &block)

Creates a new rake file under lib/tasks with the supplied tasks :

1
2
3
4
5
6
7
8
9
rakefile("bootstrap.rake") do
  <<-TASK
    namespace :boot do
      task :strap do
        puts "i like boots!"
      end
    end
  TASK
end

And that creates lib/tasks/bootstrap.rake with a boot:strap rake task!

generate(what, args)

Runs the supplied rails generator with given arguments. For example, I love to scaffold some whenever I’m playing with Rails :


generate(:scaffold, "person", "name:string", "address:text", "age:number")

run(command)

Executes an arbitrary command. Just like the backticks. My main use case is to remove public/index.html :


run "rm public/index.html"

rake(command, options = {})

So you scaffolded, but who’s gonna run the db:migrate rake task !? Here’s who :


rake "db:migrate"

Simple enough.

You can also run rake tasks in a different rails environment :


rake "db:migrate", :env => 'production'

Or even use sudo :


rake "gems:install", :sudo => true

route(routing_code)

This adds a routing entry to config/routes.rb file. In above steps, we generated a person scaffold and also removed public/index.html. Now to make PeopleController#index as the default page for the application :


route "map.root :controller => :person"

Voila!

inside(dir)

I have my edge rails lying at ~/commit-rails/rails. So every time i have to manually symlink edge from my new app. But now :

1
2
3
inside('vendor') do
  run "ln -s ~/commit-rails/rails rails"
end

So inside() runs the command from the given directory.

ask(question)

ask gives you a chance to get some feedback from the user and use it in your templates. Lets say you want your user to name the new shiny library you’re adding :

1
2
3
4
5
6
7
lib_name = ask("What do you want to call the shiny library ?")
lib_name << ".rb" unless lib_name.index(".rb")

lib lib_name, <<-CODE
class Shiny
end
CODE

yes?(question) or no?(question)

And you can even ask questions from templates and decide the flow based on user’s answer. Lets say you want to freeze rails only if the user want to :


rake("rails:freeze:gems") if yes?("Freeze rails gems ?")

no?(question) acts just the opposite.

git(:must => “-a love”)

As we all love git/hub, Rails templates let you do the git stuff too !

1
2
3
git :init
git :add => "."
git :commit => "-a -m 'Initial commit'"

And bort ?

Here’s what a bort template would look like :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# bort.rb
inside('vendor') do
  run "ln -s ~/commit-rails/rails rails"
end

plugin 'rspec', 
  :git => 'git://github.com/dchelimsky/rspec.git'
plugin 'rspec-rails', 
  :git => 'git://github.com/dchelimsky/rspec-rails.git'
plugin 'exception_notifier', 
  :git => 'git://github.com/rails/exception_notification.git'
plugin 'open_id_authentication', 
  :git => 'git://github.com/rails/open_id_authentication.git'
plugin 'asset_packager', 
  :git => 'http://synthesis.sbecker.net/pages/asset_packager'
plugin 'role_requirement', 
  :git => 'git://github.com/timcharper/role_requirement.git'
plugin 'restful-authentication', 
  :git => 'git://github.com/technoweenie/restful-authentication.git'
 
gem 'mislav-will_paginate', :version => '~> 2.2.3', 
  :lib => 'will_paginate',  :source => 'http://gems.github.com'
gem 'rubyist-aasm'
gem 'ruby-openid'
 
rake("gems:install", :sudo => true)

generate("authenticated", "user session")
generate("rspec")

Shamelessly inspired/yanked from Jeremy’s templates repo

Save that code in bort.rb and :


[lifo@null Rails]$ ruby ~/commit-rails/rails/railties/bin/rails bortapp -m bort.rb

Contribute

If you like this template stuff and want to share your templates with the rest of us, please contribute to Jeremy’s rails-templates project – which will be a collection of Rails templates.

And as usual, any bugs/feature requests can go to Rails lighthouse

UPDATE 1 Add an example of installing plugins as a git submodule. Thanks to Peter Cooper for the patch. UPDATE 2 Add an example of rake rails:template LOCATION=foo task

Ruby on Rack #2 - The Builder 13

Posted by pratik
on Tuesday, November 18

In Ruby on Rack #1 – Hello Rack! we used rackup to make port/server configurable. And rackup’s config file looked like :

1
2
# config.ru
run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}

Under the hood, rackup converts your config script to an instance of Rack::Builder.

What is Rack::Builder ?

Rack::Builder implements a small DSL to iteratively construct Rack applications.

- Rack API Docs

Rack::Builder is the thing that glues various Rack middlewares and applications together and convert them into a single entity/rack application. A good analogy is comparing Rack::Builder object with a stack, where at the very bottom is your actual rack application and all middlewares on top of it, and the whole stack itself is a rack application too.

Let’s say our rack application is called infinity :

1
2
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
Rack::Handler::Mongrel.run infinity, :Port => 9292

All infinity does is send the env hash inspect string back to the browser.

Now, there are three important Rack::Builder instance methods that you should care about :

1. Rack::Builder#run

Rack::Builder#run specifies the actual rack application you’re wrapping with Rack::Builder.

Converting infinity to use Rack::Builder:

1
2
3
4
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new
builder.run infinity
Rack::Handler::Mongrel.run builder, :Port => 9292

Or you can follow the community convention and use the block form of Rack::Builder :

1
2
3
4
5
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  run infinity
end
Rack::Handler::Mongrel.run builder, :Port => 9292

Here Rack::Builder#initialize accepts a block argument, which is evaluated within the context of newly created instance using instance_eval.

2. Rack::Builder#use

Rack::Builder#use adds a middleware to the rack application stack created by Rack::Builder. If the term “middleware” confuses you, don’t worry. Hopefully my next post will clean the air. Stick to the before/after/around filter analogy for now.

Rack has many useful middlewares and one of them is Rack::CommonLogger, which logs a single line to the supplied log file in the Apache common log format.

So if we’re to add Rack::CommonLogger to infinity :

1
2
3
4
5
6
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  use Rack::CommonLogger
  run infinity
end
Rack::Handler::Mongrel.run builder, :Port => 9292

Line of interest is of course use Rack::CommonLogger. As we didn’t supply Rack::CommonLogger with an explicit logger, by default it’ll log to env[“rack.errors”]. Hence you’ll see logging strings in the console for every request.

3. Rack::Builder#map

Rack::Builder#map mounts a stack of rack application/middlewares the specified path or URI and all the children paths under it.

Let’s say you want to show “infinity 0.1” for all the paths under /version ( i.e. /version, /version/whatever BUT NOT /versionsomething ) , you might want to do something like :

1
2
3
4
5
6
7
8
9
10
11
12
13
require 'rubygems'
require 'rack'

infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  use Rack::CommonLogger
  run infinity
  
  map '/version' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity 0.1"] }
  end
end
Rack::Handler::Mongrel.run builder, :Port => 9292

But that’s not going to work. Rack::Builder#map also encapsulates a scope within the builder. And one scope can just have one Rack::Builder#run method. In the example above, we have run infinity at the top level global scope and map ’/version’ has it’s own run too. Hence the conflict.

To fix this:

1
2
3
4
5
6
7
8
9
10
11
12
13
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  use Rack::CommonLogger
  
  map '/' do
    run infinity
  end
  
  map '/version' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity 0.1"] }
  end
end
Rack::Handler::Mongrel.run builder, :Port => 9292

Now if you go to http://localhost:9292/version or http://localhost:9292/version/1 or even http://localhost:9292/version/whatever/doesnt/matter, you’ll see “infinity 0.1” and for all the URIs not starting with /versionhttp://localhost:9292 – you’ll see the env hash inspect string!

Please note that :

  1. /versionsomething WILL NOT show the version, but will display the env inspect.
  2. When you have multiple map blocks, URIs are tried from longest length to shortest length.

Nesting map blocks

Let’s say you feel like adding information about last version. So to show “infinity beta 0.0” at /version/last:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  use Rack::CommonLogger
  
  map '/' do
    run infinity
  end
  
  map '/version' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity 0.1"] }
  end

  map '/version/last' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity beta 0.0"] }
  end
end
Rack::Handler::Mongrel.run builder, :Port => 9292

Above code will work perfectly as expected. You’ll see “infinity beta 0.0” at http://localhost:9292/version/last and “infinity 0.1” at http://localhost:9292/version.

But a better way (IMHO) to write the same code is by nesting map blocks :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}
builder = Rack::Builder.new do
  use Rack::CommonLogger
  
  map '/' do
    run infinity
  end
  
  map '/version' do
    map '/' do
      run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity 0.1"] }
    end
    
    map '/last' do
      run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity beta 0.0"] }
    end
  end
end
Rack::Handler::Mongrel.run builder, :Port => 9292

This works perfect. When you nest map blocks, you’ll need to specify URI relative to the enclosing mapping block, as you can clearly see in the example above.

Rack::Builder -> rackup

As I mentioned above, rackup converts the supplied rack config file to an instance of Rack::Builder. This is how is happens under the hood ( just so you get an idea ) :

1
2
config_file = File.read(config)
rack_application = eval("Rack::Builder.new { #{config_file} }")

And then rackup supplies rack_application to the respective webserver :


server.run rack_application, options

Very straight forward! In short, rack config files are evaluated within the context of a Rack::Builder object. So if we convert infinity to a rack config file which rackup can understand :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# infinity.ru

infinity = Proc.new {|env| [200, {"Content-Type" => "text/html"}, env.inspect]}

use Rack::CommonLogger

map '/' do
  run infinity
end

map '/version' do
  map '/' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity 0.1"] }
  end
  
  map '/last' do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "infinity beta 0.0"] }
  end
end

And now run it :

$ rackup infinity.ru

Ruby on Rack #1 - Hello Rack! 8

Posted by pratik
on Monday, November 17

Ruby community is coming up with new frameworks almost every week, but in midst of that, Rack isn’t getting enough attention. Attention that it deserves. And also, the next stable release of Rails after 2.2 will have a better public facing interface for taking full advantage of Rack.

Rack was initially inspired from pythons’s wsgi and it quickly became the de-facto web application/server interface in the ruby community, thanks to it’s simplicity and preciseness. You might want to read Introducing Rack from the creator of rack – Christian Neukirchen before reading this post.

What is Rack ?

Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.

- Rack API Docs

Practically speaking, you can divide “Rack” in two parts :

Rack Specification

Rack specification specifies how exactly a Rack application and the web server should communicate :

A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.

- Rack Specification

That’s the specification in a nutshell. You can check out the full details here.

Strictly speaking, you don’t need the rack gem in order to write Rack ready applications. Just stick to the specification and that’s it.

Rack Gem

Rack gem is a collection of utilities and facilitating classes, to make life easier for anyone developing Rack applications. It includes basic implementations of request, response, cookies & sessions. And a good number of usefult middlewares. In short, install the rack gem. You’re gonna need it :

$ sudo gem install rack

To summarize

  • Rack is a framework to roll your own ruby framework.
  • Rack provides an interface between different web servers and your framework/application. Making it very simple for your framework/application to be compatible with any webserver that supports Rack – Phusion Passenger, Litespeed, Mongrel, Thin, Ebb, Webrick to name a few.
  • Rack cuts your chase. You get request, response, cookies, params & sessions for free.
  • Makes it possible to use multiple frameworks for the same application, provided there is no class collision. Rails and sinatra integration is a good example of this.
  • Middlewares ! Think of middlewares as Rails’s before_filter/after_filter that are reusable across different rack supported frameworks/applications. For example, you can use the same Anti-spamming rack middleware for your Rails app, Sinatra app and your custom Rack application too!

Examples

Let’s start with a smallest possible example of a rack application, using mongrel.

1
2
3
4
5
6
7
8
9
10
require 'rubygems'
require 'rack'

class HelloWorld
  def call(env)
    [200, {"Content-Type" => "text/html"}, "Hello Rack!"]
  end
end

Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

The above code passes an object of HelloWorld to the mongrel rack handler, and starts the server on port 9292.

The HelloWorld object here respects the rack specifications. That is :
  1. Responds to call(), which takes one argument – environment
  2. call() returns an Array of [http_status_code, response_headers_hash, body]

That’s all ! If you run this script and browse to http://localhost:9292, you’ll see the shiny “Hello Rack!” message.

But hey, even a ruby proc responds to call(). So why not use a proc instead ? Well, no reason not to :

1
2
3
4
require 'rubygems'
require 'rack'

Rack::Handler::Mongrel.run proc {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}, :Port => 9292

Another common seen pattern is to use method(:something), which returns an object of Method class :

1
2
3
4
5
6
7
8
require 'rubygems'
require 'rack'

def application(env)
  [200, {"Content-Type" => "text/html"}, "Hello Rack!"]
end

Rack::Handler::Mongrel.run method(:application), :Port => 9292

Take that you “Hello World” performance retards. You’re not gonna be able to write a faster ‘Hello World’ ruby application than this.

Rack it up’

As I said earlier, rack gem comes with a bunch of useful stuff to make life easier of a rack application developer. rackup is one of them. In the previous examples, I had used the mongrel handler Rack::Handler::Mongrel directly, and even hard coded the port number. With rackup, these things become configurable ! But to use rackup, you’ll need to supply it with a rackup config file. For our above example, the config file will look somewhat like :

1
2
# config.ru
run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}

Just a line. By convention, you should use .ru extension for a rackup config file. Supply it a run RackObject and you’re ready to go :

$ rackup config.ru

By default, rackup will start a server on port 9292. But you can override that with a -p option to rackup. For more help, RTFM:

$ rackup --help

Rails meets Sinatra #2 - Mix n' Match 8

Posted by pratik
on Sunday, November 16

In my previous post, we saw how to mount a sinatra application at a specific location for a regular application. But using Rack::Cascade, we can take that solution to a whole new height. That is :

  • Put sinatra code in any of your regular Rails controllers.
  • No need to mount at Sinatra at a specific URI.
  • Have Sinatra work for any URI, gracefully fallback to Rails if no Sinatra method matches the path.
  • Use your models/libraries etc. in both Rails and Sinatra.

So your controllers can look like :

1
2
3
4
5
6
7
8
class HomeController < ApplicationController
  get '/' do
    Item.count.to_s
  end
  
  def index
  end
end

and even :

1
2
3
4
5
6
7
8
9
class SiteController < ApplicationController
  get '/:name' do
    Site.find_by_name(params[:name]).html
  end

  def new
  end

end

And environment.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
RAILS_GEM_VERSION = '2.2.0' unless defined? RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot')

Rails::Initializer.run do |config|
  config.gem "sinatra"
  config.time_zone = 'UTC'
  config.action_controller.session = { :session_key => '_monkey_session',  :secret => 'whatever' }
end

set :env, :production
disable :run, :reload

# Remove trailing slash from URIs reaching Sinatra
before { request.env['PATH_INFO'].gsub!(/\/$/, '') if request.env['PATH_INFO'] != '/' }

# Checking AR Connections back to the pool
after { ActiveRecord::Base.clear_active_connections! }

# Preload controllers with Sinatra code
require 'home_controller'
require 'site_controller'

And most important, the rack setup file :

1
2
3
4
5
6
7
8
9
require File.dirname(__FILE__) + '/config/environment'
require 'thin'
  
app = Rack::Builder.new {
  use Rails::Rack::Static
  run Rack::Cascade.new([Sinatra.application, ActionController::Dispatcher.new])
}.to_app
 
Rack::Handler::Thin.run app, :Port => 3000, :Host => "0.0.0.0"

And start your server !

[lifo@219 monkey]$ ruby racked.rb

Rails meets Sinatra 11

Posted by pratik
on Monday, November 10

For real !

It was pleasantly simple to get Rails + Sinatra run in the same process.

First of all, put your Sinatra application inside RAILS_ROOT. My Sinatra app is called tiny :

1
2
3
4
5
6
7
8
# RAILS_ROOT/tiny.rb
require 'sinatra'

before { request.env['PATH_INFO'].gsub!(/\/$/, '') }

get '' do
  'Hello Sinatra!'
end

And then do the rack dance – racked.rb :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# RAILS_ROOT/racked.rb
require File.dirname(__FILE__) + '/config/environment'
require 'thin'
 
# Sinatra stuff
require 'tiny'
 
# Make sinatra play nice
set :env, :production
disable :run, :reload
 
app = Rack::Builder.new {
  use Rails::Rack::Static
 
  # Anything urls starting with /tiny will go to Sinatra
  map "/tiny" do
    run Sinatra.application
  end
 
  # Rest with Rails
  map "/" do
    run ActionController::Dispatcher.new
  end
}.to_app
 
Rack::Handler::Thin.run app, :Port => 3000, :Host => "0.0.0.0"

Line 25 ensures your Sinatara application is used for all the urls starting from /tiny. Any url not starting from /tiny will go to the Rails application.

Now start your server :

$ ruby racked.rb

If you go to http://0.0.0.0:3000/tiny, you’ll be greeted with ‘Hello from sinatra!’. And your Rails application will continue to work as expected for everything else. Voila! There you have the fastest ‘hello world’ Ruby framework embedded with Rails :)

Please note that Rails’ built in rack adapter isn’t perfect and you might find a glitch or two. All in good time

UPDATE 1: Prettify Sinatra code and remove monkey patches, thanks to the feedback from Blake Mizerany. Also add a before filter to sinatra app for removing trailing slash.

ActiveSupport::Rescuable 3

Posted by pratik
on Monday, November 03

In Rails 2.2, controller’s rescue_from has been extracted to ActiveSupport as ActiveSupport::Rescuable module. Relevant commits are 964dfc and 259a7a. This allows you to use rescue_from functionality in class as a cleaner way of handling exceptions.

Now you can just include ActiveSupport::Rescuable in your class and start using rescue_with_handler(exception) from your rescue blocks :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Armageddon < StandardError
end

class Earth
  include ActiveSupport::Rescuable

  rescue_from Armageddon, :with => :nuke_the_rock

  def life
    raise Armageddon
  rescue Exception => e
    rescue_with_handler(e)
  end

  def nuke_the_rock
    puts "snafu"
  end
end

e = Earth.new
e.life

The above code will produce output “snafu”. You can also check code/docs if you wanna know more.

Thread safety for your Rails 34

Posted by pratik
on Friday, October 24

Rails 2.2 marks the first release of thread safe Rails. But “thread safety” alone, without any context, doesn’t mean shit. When people say Rails is “thread safe” ( or otherwise ), they usually refer to the dispatching process of Rails. Before 2.2, Rails dispatching looked like :

1
2
3
@@guard.synchronize do
  dispatch_unlocked
end

And now it looks somewhat like :


dispatch_unlocked

Long story short, Rails can now serve multiple requests in more than one ruby threads ( or native threads if you’re on JRuby ) parallelly. Charles Nutter has done a good job of explaining the details here.

Should you give a flying fuck ?

You totally should if :

  • You’re using JRuby
  • You’re bold enough to play around with bleeding edge Neverblock stuff
  • Your application has a lot of long running processes, which are not heavy on blocking IO ( this would be rare I imagine )

You totally should NOT if :

  • You’re using Event based mongrel, thin or any of the event based web server in production. Event based servers don’t use Threads, so it just doesn’t matter.
  • You CBA

You may have heard a bunch of hype about how threads make everything 100x faster, this is far from the truth. Don’t believe everything the hype merchants want to sell you, test your application first and see if it helps.

Koz’s comments sums it up nicely :

I think the more interesting issue to consider is whether your application will benefit from ‘threaded dispatching’ at all.

The performance of green threads in ruby is kind of disappointing, as are the number of different options which block the interpreter. IO, regexps, calling most native libraries, etc. Odds are with matz’s ruby you’re infinitely better off using passenger + ruby enterprise edition than ruby threads.

JRuby is another matter altogether, and it’s jruby users who should be most excited about this stuff, and the most willing to help us iron out any last bugs.

Prepare your mongrels first

Currently, you’ll need to manually patch Mongrel’s built in Rails handler for testing multithreaded dispatching. I’ve submitted a patch to mongrel and hopefully there’ll be a new gem version of mongrel soon. In the mean time, monkey patch FTW.

How to enable multi threaded dispatching ?

Just put the following lines in your production.rb


config.threadsafe!

However, that’s not enough. There are some consequences if you have never made sure to write thread safe code. They are, however, simple to fix. Usually.

Ruby’s require is not atomic

What this means is, if in Thread A you require a file named whatever.rb in which defines a class called Whatever, the class Whatever can be visible from Thread B even before Thread A has finished loading whatever.rb. And because of this ruby behavior, Rails now preloads everything inside app directory.

config.threadsafe! also disables automatic loading by ActiveSupport::Dependencies.

ActiveSupport::Dependencies uses ruby’s const_missing hook to load files automatically for you, whenever possible. For example, if you have following file inside your application’s lib/ directory :

1
2
3
4
5
6
# hello.rb
class Hello
  def world
    "hello world"
  end
end

Rails has traditionally saved you the trouble of requring that file manually inside your application. Whenever you access Hello ( Hello.new for example ) constant for the first time, ActiveSupport::Dependencies loads hello.rb for you automatically. Note that this is only possible if the file name matches the class name that it defines.

But as this behavior is disabled when you calls config.threadsafe!, you’ll now need to require the file hello.rb manually before Rails starts serving the requests ( typically inside environment.rb or an initializer ).

Alternatively, you can just add lib/ directory to eager load paths. The following inside production.rb will do that :


config.eager_load_paths << "#{RAILS_ROOT}/lib"

And that will make Rails preload everything inside lib/ directory.

Don’t mess with class variables

Imagine your controller having a code that does :

1
2
3
4
5
6
7
8
class HomeController < ApplicationController
  @@visits = 0
  
  def index
    @@visits += 1
    render :text => @@visits
  end
end

This code is not safe if you enable multi threaded dispatching. All your instance methods ( actions in case of controllers ) should only read global values ( $vars, @@vars, class instance variables ) and never modify them.

Here’s a better example which would explains the consequences as well :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class HomeController < ApplicationController
  before_filter :set_site
  
  def index
  end
  
  private
  
  def set_site
    @site = Site.find_by_subdomain(request.subdomains.first)
    if @site.layout?
      self.class.layout(@site.layout_name)
    else
      self.class.layout('default_lay')
    end
  end
end

What happens here is :

  • Before filter set_site uses subdomain to populate @site instance variable
  • It also sets the layout to @site.layout_name is not nil

Imagine your application has two possible subdomains :

  • foo – has a layout called ‘foo_lay’
  • bar – has no layout. Uses default layout ‘default_lay’

When you call self.class.layout(value), Rails will store the value inside a class variable @@layout, which causes a race condition if called from multiple instance methods in different threads. Wikipedia page will do a better job of explaining what is a race condition if you have never bothered about it before.

Let us assume that two users are accessing the application : UserA and UserB. UserA’s request is served by Thread1 and UserB’s request is served by Thread2. Here, numbers also represent the order in which these events occur :

  1. Thread1 : UserA visits http://foo.site.com/home
  2. Thread1 : HomeController#set_site calls self.class.layout(@site.layout_name)
  3. Thread1 : This sets HomeController#@@layout to ‘foo_lay’
  4. Thread2 : UserB visits http://bar.site.com/home
  5. Thread2 : HomeController#set_site calls self.class.layout(‘default_lay’)
  6. Thread2 : This sets HomeController#@@layout to ‘default_lay’
  7. Thread1 : Request is done executing action code. Time to send back the response to UserA.
  8. Thread1 : Rails calls HomeController#render
  9. Thread1 : HomeController#render uses the value of HomeController#@@layout to render the final output html
  10. Thread1 : As the value of HomeController#@@layout was modified by #6 to ‘default_lay’, #9 will uses ‘default_lay’ even if the expected layout was ‘foo_lay’

The thread safe way to write this code is :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class HomeController < ApplicationController
  before_filter :set_site
  layout :site_layout

  def index
  end
  
  private
  
  def set_site
    @site = Site.find_by_subdomain(request.subdomains.first)
  end
  
  def site_layout
    if @site.layout?
      @site.layout_name
    else
      'default_lay'
    end
  end
end

When you use layout :site_layout, Rails will use the return value of site_layout instance method to determine the layout, which makes it a thread safe way. Please note that this is not the same as calling layout ‘something’. If you pass a string to the class method layout, Rails will use the passed value as the layout.

( Example inspired from Dynamic Layouts Railscast )

Getting dirty with Thread.current

if you must, you can always use Thread local variables as the last resort. Ruby provides you with a magical hash Thread.current[] inside any executing thread, where you can store variables accessible anywhere from inside that specific thread. Really, you can check this docs

The following code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
threads = []

threads << Thread.new do
  Thread.current[:hello] = 1
  sleep 2
  puts "From T1 : #{Thread.current[:hello]}"
end

threads << Thread.new do
  Thread.current[:hello] = 10
  puts "From T2 : #{Thread.current[:hello]}"
end

threads.each {|t| t.join }

will produce :

1
2
From T2 : 10
From T1 : 1

You might have seen this in use in with any current_user hacks : Here or here. But it’s still a hack.

If you’re familiar with Rails source ( of interested in being familiar ), you can find Rails using Thread.current[] at several places : Thread.current[:time_zone] or Thread.current[‘query_cache’]. I18 gem uses Thread.current[:locale] to store the value of locale specific to the thread.

But as I said earlier, Thread.current should be used as a last resort only.

Good ol’ Mutex

There is always the big fat mutex which can be slapped around a piece of code that you want to execute exclusively per thread. You should check the wikipedia page if you’re looking for some explanation :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class HomeController < ApplicationController
  @@lock = Mutex.new

  def index
    @@lock.synchronize do
      thread_unsafe_code
    end
  end
  
  private
  
  def thread_unsafe_code
    if @@something == 'hello'
      do_hello
    elsif @@something == 'world'
      do_world
    else
      @@something = 'nothing'
    end
  end
end

This ensures that only one thread can be executing thread_unsafe_code() method at any given point in time. Other threads will block and wait indefinitely for the executing thread to release the lock acquired by @@lock.synchronize.

Common concerns

Adam Hooper raised three valid concerns :

  • What is the likelihood that there is broken code in the Rails core, despite the word “threadsafe!”? If Java frameworks (engineered in a language which, unlike Ruby, was built from the ground up with threads in mind) can provide premonitions, is it not safe to assume Rails is painfully buggy in this regard?

Chances of thread unsafe code being in Rails are close to none. There have never been anything inherently thread unsafe about Rails codebase. If some people had you think otherwise, you listened to the wrong bunch of people/FUD. We’ve had a list of thread unsafe code inside Rails for a long time, and it was a small list.

However, thread safety is like a Random Number Generator – You can never be sure

  • All existing plug-ins are thread-unsafe until proven otherwise, right? (And IMO Rails developers should broadcast this at the top of their voices, because promising thread-safety and relying on other people to provide it is shooting oneself in the foot….)

Jeremy says : No. They are not. Most, in fact, are probably threadsafe. Your claiming this is a major issue is a fairly good indicator that you don’t actually know the core issues with thread safety in Ruby/Rails.

Me : That’s not true. At least all the plugins that I use, are thread safe. Having said that, you should never use a plugin without getting yourself familiar with it’s code base.

  • Does anybody think thread-safe Rails will ever be suitable for production use? It’s hard enough to convince a project manager to consider it already, with its current, much, much, much, MUCH simpler model.

Short answer, don’t jump the ship if you can’t be bothered about ensuring your code is thread safe. Always stick to “Simplest thing that works” motto IMO. You could just spend some time researching if running multithreaded Rails is going to benefit your application/business at all or not and evaluate that against the risk/time involved.

But that doesn’t make threadsafe Rails unsuitable for production use. It makes your specific application/team unsuitable for using thread-safe Rails in production mode. Multi threaded programming has never been easy. However, if you write good OO code, thread safety usually comes for free.

UPDATES :
  1. Added Mutex section.
  2. Added ‘Common concerns’
  3. Added ‘Should you give a flying fuck ?’
  4. Added ‘Prepare your mongrels first’

Sanity for free 5

Posted by pratik
on Sunday, October 05

Just an experiment.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
require 'erb'

class ActionView::Base
  def _copy_ivars_from_controller_with_sanity
    variables = _copy_ivars_from_controller_without_sanity
    variables.each do |v|
      ivar = instance_variable_get(v)
      if ivar.is_a?(Array)
        values = ivar.map do |subivar|
          subivar.respond_to?(:to_sanity) ? subivar.to_sanity : subivar
        end
        instance_variable_set(v, values)
      elsif ivar.respond_to?(:to_sanity)
        instance_variable_set(v, ivar.to_sanity)
      end
    end
  end

  alias_method_chain :_copy_ivars_from_controller, :sanity
end

module Sanity
  class Cleaner
    Object.instance_methods.each do |m|
      delegate m, :to => :@model unless m =~ /^__/
    end
    
    def initialize(model)
      @model = model
    end

    def method_missing(method_id, *arguments, &block)
      if @model.class.sanitizable_columns.include?(method_id)
        value = @model.send(method_id)
        arguments.first == false ? value : ERB::Util.h(value)
      else
        @model.send(method_id, *arguments, &block)
      end
    end
  end

  module Model
    def self.included(base)
      base.send :include, InstanceMethods
      base.send :extend, ClassMethods
    end
    
    module InstanceMethods
      def to_sanity
        Cleaner.new(self)
      end
    end
    
    module ClassMethods
      def sanitizable_columns
        @sanitizable_columns ||= content_columns.find_all {|c| c.text? }.map(&:name).map(&:to_sym)
      end
    end
  end
end

ActiveRecord::Base.send :include, Sanity::Model

And then..

1
2
<%= @item.name # sanitized name %>
<%= @item.name(false) # unsanitized name  %>

I know, too many methods are missing, edge cases and what not. But hey, it’s just an idea/experiment.

Poor man's migrations 6

Posted by pratik
on Wednesday, September 17

In case you have read PJ’s post on Automatic migrations you might like this.

PoorMansMigrations is a very simple Active Record extension that allows you to create/update/delete DB columns without using migrations directly.

Playing with your models can be as easy as :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require 'rubygems'
require 'activerecord'
require 'poor_mans_migrations'

ActiveRecord::Base.establish_connection :adapter  => "mysql", :host => "localhost",  :username => "root", :database => "property_db"
ActiveRecord::Base.logger = Logger.new($stdout)

class User < ActiveRecord::Base
  column :age, :string
  column :name, :string
  column :admin, :integer, :default => 0
end

User.migrate

u = User.create :age => '1000', :name => 'whatever'

Doing Model.migrate will automatically sync the database table with the columns you define inside your models. That is, if you add new column :what, :ever statements, those columns will be created in the table. Similarly, if you remove any column statements, respective columns will be removed from the table.

But hey, thats just stupid. Age is integer silly! Changing the column is a little tricky. As I didn’t want the library to be super smart in figuring out what changed when, I just used a simple/stupid/verbose solution. If you supply :force => true option to column definition, the column will be dropped and recreated when you do Model.migrate

So the following will fix the age column :

1
2
3
4
5
class User < ActiveRecord::Base
  column :age, :integer, :force => true
end

User.migrate

And if you royally screw up, and just want to start everything from scratch :


User.migrate!

Migrate with a !

Here’s the code for PoorMansMigrations :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# Released under WTFPL - http://sam.zoy.org/wtfpl/
module PoorMansMigrations
  def self.extended(base)
    base.class_inheritable_accessor :migration_columns
    base.migration_columns = []
  end

  def column(name, type, options = {})
    self.migration_columns << {:column_name => name, :column_type => type, :options => options}
  end

  def realize!(force_drop = false)
    # Force drop if needed
    connection.drop_table(table_name) if force_drop && table_exists?
    
    # Create table
    connection.create_table(table_name) {|t| } unless table_exists?
    
    self.migration_columns.each do |p|
      #haxhaxhax - Force reload reading column names. Whatever.
      reset_column_information
      column_exists = column_names.include?(p[:column_name].to_s)

      # Delete the columns if forced to
      if p[:options].delete(:force) && column_exists
        connection.remove_columns(table_name, p[:column_name])
        column_exists = false
      end

      connection.add_column(table_name, p[:column_name], p[:column_type], p[:options]) unless column_exists
    end
  end
  
  def clean_leftover_columns!
    return unless table_exists?
    reset_column_information
    
    left_overs = column_names - self.migration_columns.map {|m| m[:column_name].to_s} - Array(primary_key)
    connection.remove_columns(table_name, left_overs)
    reset_column_information
  end
  
  # Force recreation for everything
  def migrate!
    realize!(true)
    clean_leftover_columns!
  end

  # Take it easy. Only force if specified in column definition
  def migrate
    realize!
    clean_leftover_columns!
  end
end

ActiveRecord::Base.send :extend, PoorMansMigrations
You get the Gist

Main purpose of PoorMansMigrations is to make it very simple to play around with Active Record, independent of Rails. In stand alone scripts, etc. It should be very simple for anyone to write the needed plugin in order to use it in regular Rails apps. PDI.

Please note that you would never want to use this code/method in any production application. Destructive migrations can cost you your job.

UPDATE 1 : I had made a schoolboy error in the initial version of the code, by not using class inheritable attributes. It’s been fixed now.