martinciu’s dev blog

about ruby, rails, javascript, nodejs, coffeescript, objective-c, swift

Deploying Hubot to Heroku Like a Boss

What is Hubot?

Hubot was an almost mythical GitHub campfire bot. They use it for deploying, automate a lot of tasks, and to be a source of fun in the company. Was, because they open sourced it some time age.

Hubot & Heroku

When I decided to give hubot a try on Heroku I googled for it and found a few tutorials and blog posts. All of them advise to download (or clone) main hubot repository and deploy it to heroku. In may opinion this is not the best way to do it. This post describes how to create separated deployable hubot application.

Tools needed

You will need a ruby, git, node.js, npm and a heroku gem installed. Ruby and git is pretty common. You will install heroku gem by:

$ gem install heroku

then node.js with Homebrew

$ brew install node

and npm

$ curl http://npmjs.org/install.sh | sh

Things done locally

Clone hubot repository and create a new directory that will deployed to heroku.

$ git clone git://github.com/github/hubot.git
$ cd hubot
$ npm install    # install all required dependencies
$ bin/hubot --create ../acmebot

If you go to the created directory you should see file structure similar to this:

$ cd ../acmebot
$ ls -l
~/www/blog/hubot/acmebot  
total 32
-rw-r--r--   1 martinciu  staff    36 31 paź 21:28 Procfile
-rw-r--r--   1 martinciu  staff  3411 31 paź 21:28 README.md
drwxr-xr-x   3 martinciu  staff   102 31 paź 21:28 bin
-rw-r--r--   1 martinciu  staff    56 31 paź 21:28 hubot-scripts.json
-rw-r--r--   1 martinciu  staff   518 31 paź 21:28 package.json
drwxr-xr-x  12 martinciu  staff   408 31 paź 21:28 scripts

This will be your hubot application that you will deploy to heroku. First create a new git repository.

$ git init .
$ git add .
$ git commit -m "initial commit"

Now you can create a new heroku app.

$ heroku create acmebot --stack cedar

And now you can deploy your own hubot to heroku.

$ git push heroku

Heroku configuration

It is deployed, but hubot won’t join any campfire room because it doesn’t know anything about it. You have to tell him what room(s) should he go to. You can do it by heroku configuration variables.

# Campfire user's token. You can find it on user's profile pages.
# You should probably have additional campfire user for a hubot 
$ heroku config:add HUBOT_CAMPFIRE_TOKEN=secret
# room ids coma-separated (you can find room id in room URL)
$ heroku config:add HUBOT_CAMPFIRE_ROOMS=123 
# your campfire account subdoamin
$ heroku config:add HUBOT_CAMPFIRE_ACCOUNT="acme"

For some scripts Redis is required. You can add a free RedisToGo service by typing:

$ heroku addons:add redistogo:nano

All is set up. Now you can start hubot:

$ heroku ps:scale app=1

It’s alive!

Now if you go to you campfire room and type

$ Hubot help

you should get a list of commands that your Hubot is familiar with.

When it is not alive :/

If hubot doesn’t speak to you, it means that something went wrong. In that case you can check heroku logs by typing in console:

$ heroku logs

You can also check application status by typing:

$ heroku ps

More scripts

You have just deployed a basic hubot set up. If you want to add more commands you can find them on the hubot-scripts repository. It is already added to you your copy of hubot. To turn it on you should edit hubot-scripts.json file. It is simple JSON file with list of custom scripts that should be loaded. At the time of writing some of the scripts that are available in the hubot-scripts repository are not yet available on the npm. So if your hubot doesn’t start after adding some custom scripts, check it’s log files to see what scripts can’t be found.

Robot’s name

Hubot only talks to you if you call him by name. And it is a new of the user who’s token hubot uses. You can specify that name in the Procfile

app: bin/hubot --adapter campfire --name acmebot --enable-slash

And if you don’t want to talk to hubot by name you can add --enable-slash option. It will allow to replace robot’s name with /. Example:

/mustache me lady gaga

How to Add API Throttle to Your Rails App

Does your app have API?

Yes? That’s awesome! But are you sure that it is safe? And I don’t mean if you secured access with api_key, Basic HTTP or anything like this. I mean if it is safe for your severs? At zubibu we are going to add API for updating items in customer shops. It is pretty simple and obvious method. But if some API client use it in bad way it can harm us. For example, if an online store with 400 thousands items decided to decrease all prices by 2% for each item, and if they implemented zubibu API call after each item update - it could harm us. 400k requests in a very short period of time could be dangerous for many apps.

How to protect your API?

You can educate your clients :), you can implement queue for handling API calls on your side. But in most cases (or at least in case described above) queue should be done on the client side. To force implementing queue on the client side you could use API throttling. It should as light as possible and invoked as soon as possible in request processing. So the Rack app sound perfect for this task. You can write your own api throttling app or you can use rack-throttle gem. It is simple but has almost all required features and is pretty easy to extend. We at zubibu needed some custom features, so we decided to extend Rack::Throttle::Limiter. This is our implementation of API throttle. I home comments in code are enough to understand it.

# lib/api_defender.rb
require 'rack/throttle'
# we limit daily API usage
class ApiDefender < Rack::Throttle::Daily

  def initialize(app)
    host, port, db = YAML.load_file(File.dirname(__FILE__) + '/../config/redis.yml')[Rails.env].split(':')
    options = {
      # we already use Redis in our app, so we reuse it's 
      # config file here
      :cache => Redis.new(:host => host, :port => port, :thread_safe => true, :db => db),
      # if you use staging environment on the same redis server
      # it is good to have separete key prefix for this
      :key_prefix => "zubibu:#{Rails.env}:api_defender",
      # only 5000 request per day
      :max => 5000
    }
    @app, @options = app, options
  end

  # this method checks if request needs throttling. 
  # If so, it increases usage counter and compare it with maximum 
  # allowed API calls. Returns true if a request can be handled.
  def allowed?(request)
    need_defense?(request) ? cache_incr(request) <= max_per_window : true
  end

  def call(env)
    status, heders, body = super
    request = Rack::Request.new(env)
    # just to be nice for our clients we inform them how many
    # requests remaining does they have
    if need_defense?(request)
      heders['X-RateLimit-Limit']     = max_per_window.to_s
      heders['X-RateLimit-Remaining'] = ([0, max_per_window - (cache_get(cache_key(request)).to_i rescue 1)].max).to_s
    end
    [status, heders, body]
  end

  # rack-throttle can use many backends for storing request counter.
  # We use Redis only so we can use it's features. In this case 
  # key increase and key expiration
  def cache_incr(request)
    key = cache_key(request)
    count = cache.incr(key)
    cache.expire(key, 1.day) if count == 1
    count
  end

  protected
    # only API calls should be throttled
    def need_defense?(request)
      request.host == API_HOST
    end

end

To add this to your application you to add rack-throttle to your Gemfile

# Gemfile
#...
gem 'rack-throttle'

and run bundle install

after that add, ApiDefender middleware to your app’s rack stack. It should go as high in the stock as possible:

# config/applicaiton.rb
require 'lib/api_defender'
module SomeAwesomeApp
  class Application < Rails::Application
    # ...
    config.middleware.insert_after Rack::Lock, ApiDefender
  end
end

And thats it! Now, when you access your API you should get response like this:

$ curl -I http://api.someawesomeapp.com/whatever
HTTP/1.1 200 OK
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4999

but if you exceed 5000 API calls you will get this response:

HTTP/1.1 403 Forbidden
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 0

And voilà, your API is more safe now!

More modifications

I suggest you reading rack-throttle’s README file as well as it’s source code to find out what else you could easily modify for your needs. For example your ApiDefence middleware could extend Rack::Throttle::Hourly instead of Rack::Throttle::Daily. Your could use different counter store, or identify your clients differently by overriding client_identifier method.

Upgrading to Rails 3.1.0.rc5 (From Rc4)

Rails 3.1.0.rc5

Rails 3.1.0.rc5 is out. If your app doesn’t use rails 3.1 yet you may want to read this and probably this. If you have balls and you already use version 3.1, you probably would like to use rc5 ASAP.

Surprise

Alright RC releases could not be much different from each other. You may think that simple change in Gemfile make you even more cool.

gem 'rails', '3.1.0.rc5'

Not this time :). After changing Gemfile and running

$ bundle update rails

this line of my template:

# app/views/layouts/application.html.haml
= stylesheet_link_tag :contents, :media => "screen,print"

throws this error:

No expansion found for :contents

What has been changed?

After each major rails upgrade it is always good to generate dummy app and look around what has been changed. I did it and found two little things.

There is a new group in Gemfile called assets.

# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem 'sass-rails', "~> 3.1.0.rc"
  gem 'coffee-rails', "~> 3.1.0.rc"
  gem 'uglifier'
end

And config/application.rb file has been changed in the way how bundler require gems:

# config/application.rb
Bundler.require *Rails.groups(:assets) if defined?(Bundler)

After implementing these changes my app is working under rails 3.1.0.rc5. Hooray!

There may be other differences but none of them breaks my app.

Difference Between Class_inheritable_attribute and Class_attribute

Deprecation warning

After you upgrade to Rails 3.1 you may be attacked by deprecation warnings similar to this one:

DEPRECATION WARNING: class_inheritable_attribute is deprecated, please use class_attribute method instead. Notice their behavior are slightly different, so refer to class_attribute documentation first. (called from included at base.rb:2)

In most case it will probably be all right to replace your all class_inheritable_hash, class_inheritable_array, etc method with class_attribute. Unfortunately it won’t always work. There is a “slight” difference mentioned by warning above.

What is the difference?

With class_inheritable_hash (the old way):

class Base
  class_inheritable_hash :mappings
  self.mappings = {}
end

class FirstChild < Base
  self.mappings[:foo] = :bar
end

class SecondChild < Base
  self.mappings[:bar] = :baz
end

Base.mappings           # {}
FirstChild.mappings     # {:foo=>:bar}
SecondChild.mappings    # {:bar=>:baz}

Alright, this is the expected behavior. How does this code works with class_attribute? Let’s see!

class Base
  class_attribute :mappings
  self.mappings = {}
end

class FirstChild < Base
  self.mappings[:foo] = :bar
end

class SecondChild < Base
  self.mappings[:bar] = :baz
end

Base.mappings           # {:foo=>:bar, :bar=>:baz}
FirstChild.mappings     # {:foo=>:bar, :bar=>:baz}
SecondChild.mappings    # {:foo=>:bar, :bar=>:baz}

It is far from the how it supposed to work. I would’t say that class_attribute behavior is “slightly” different than “class_inheritable_hash”. It is completely different method! But there is no place for complaining. We have to deal with it. How can we do it? Actually quite simple. Just call dup method on an inheritable attribute:

class Base
  class_attribute :mappings
  self.mappings = {}
end

class FirstChild < Base
  self.mappings = self.mappings.dup
  self.mappings[:foo] = :bar
end

class SecondChild < Base
  self.mappings = self.mappings.dup
  self.mappings[:bar] = :baz
end

Base.mappings           # {}
FirstChild.mappings     # {:foo=>:bar}
SecondChild.mappings    # {:bar=>:baz}

Exactly as expected! Hooray!

Building Your Own Hoptoad App Clone With Errbit, VMware Cloud Foundry and MongoDB

Disclaimer

Please note that VMware Cloud Foundry is under heavy development right now. It means that some of the things written below might not be valid at time you are reading it. Please leave a comment if you find any outdated stuff.

Errbit

Errbit is an open source, self-hosted error catcher. It is Hoptoad API compliant so you can just point the Hoptoad notifier at your Errbit server if you are already using Hoptoad.

Because Errbit is self-hosted solution you need to have a decent server to run it. You can run it on you own server, you can run it on heroku - details in Errbit’s Readme or you can use Cloud Foundry. This post is a simple tutorial how to do it.

What is VMware Cloud Foundry

Cloud Foundry is the open platform as a service project initiated by VMware. It can support multiple frameworks, multiple cloud providers, and multiple application services all on a cloud scale platform.

You can download from Cloud Foundry from GitHub repository and set up your own cloud infrastructure or you can use hosted by VMware one. In this tutorial we use hosted one.

Cloud Foundry account and VMC tools

At first we need a Cloud Foundry account. They was at closed beta at the time I sign up. I had to wait a few days to get an account. I don’t know if it still apply. After you get an account install Cloud Foundry VMC tools. VMC is a command line client for Cloud Foundry.

$ gem install vmc

Then log in to Cloud Foundry using credentials.

$ vmc login  
Email: marcin.ciunelis@gmail.com
Password: ******
Successfully logged into [http://api.cloudfoundry.com]

You may want to change automatically generated password. You can do that using VMC tools:

$ vmc passwd  
Changing password for 'marcin.ciunelis@gmail.com'
New Password: ******
Verify Password: ******

Successfully changed password

Errbit

Errbit will not work out of the box on Cloud Foundry. We need to modify it a little. I won’t write here how to set up Errbit on your local box. You can find it on project README file. I’m going to focus on Cloud Foundry specific issues mainly. First, clone it from GitHub repository.

$ git clone git://github.com/jdpace/errbit.git

When you open Gemfile you will notice that redmine_client gem is taken from git repository, not from official gem release because official one does not work with Rails3. If you are not going to use Redmine integration you can safely comment that line out. If want to use Redmine you we will need to figure out something smarter :)

# Gemfile
gem 'lighthouse-api'
# gem 'redmine_client', :git => "git://github.com/oruen/redmine_client.git"
gem 'mongoid_rails_migrations'
#...

The other thing that Cloud Foundry currently does not support is running rake task. Errbit requires running rake errbit:bootstrap which copy config/config.yml, config/mongoid.yml files and seed the database. You can run this task on your local box to create config files.

$ rake errbit:bootstrap
Copying example config files...
-- Copying config/config.example.yml to config/config.yml
-- Copying config/deploy.example.rb to config/deploy.rb
-- Copying config/mongoid.example.yml to config/mongoid.yml

Seeding database
-------------------------------
Creating an initial admin user:
-- email:    errbit@errbit.example.com
-- password: password

Be sure to change these credentials ASAP!

Generating indexes for App
Generating indexes for Err
Generating indexes for Notice
Generating indexes for User

Edit config/config.yml file amending host (it must be uniqe) and email_from lines. Also production section in your config/mongoid.yml file should looks like this:

production:
  host: <%= JSON.parse( ENV['VCAP_SERVICES'] )['mongodb-1.8'].first['credentials']['hostname'] rescue 'localhost' %>
  port: <%= JSON.parse( ENV['VCAP_SERVICES'] )['mongodb-1.8'].first['credentials']['port'] rescue 27017 %>
  database:  <%= JSON.parse( ENV['VCAP_SERVICES'] )['mongodb-1.8'].first['credentials']['db'] rescue 'errbit_development' %>
  username: <%= JSON.parse( ENV['VCAP_SERVICES'] )['mongodb-1.8'].first['credentials']['username'] rescue '' %>
  password: <%= JSON.parse( ENV['VCAP_SERVICES'] )['mongodb-1.8'].first['credentials']['password'] rescue '' %>

Because we use JSON here to decode mongodb configuration, you will add the following line to your Gemfile

gem 'json'

and run bundle install command

To seed database we need to use a little trick. Errbit already use mongoid_rails_migrations so we can use rails migration to do this. Generate migration:

$ rails generate migration seed_database

and modify to look like this:

class SeedDatabase < Mongoid::Migration
  def self.up
    Rake::Task['db:seed'].invoke
    Rake::Task['db:mongoid:create_indexes'].invoke
  end

  def self.down
  end
end

One more thing before deploying. Errbit will send an email when error occur in your app. So you should have an valid delivery_method configured. It may be your own SMTP server, Amazon SES or email app like Sendgrid or PostmarkApp

Deploy

To run Errbit we need two servers. One for web-server and one for MongoDB database. Setting this up is really simple. To setup the app and database server type:

$ vmc push errbit --path=. --url=martinciu-errbit.cloudfoundry.com --mem=128M --runtime=ruby19
Detected a Rails Application, is this correct? [Yn]: 
Creating Application: OK
Would you like to bind any services to 'errbit'? [yN]: y
The following system services are available::
1. mongodb
2. mysql
3. redis
Please select one you wish to provision: 1
Specify the name of the service [mongodb-e776e]: 
Creating Service: OK
Binding Service: OK
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (9K): OK   
Push Status: OK
Staging Application: OK                                                         
Starting Application: OK

--url should be same as the one you entered in config/config.yml file and it should be unique. That’s it you should have now a working application. You can check working apps by

$ vmc apps

+-------------+----+---------+-----------------------------------+---------------+
| Application | #  | Health  | URLS                              | Services      |
+-------------+----+---------+-----------------------------------+---------------+
| errbit      | 1  | RUNNING | martinciu-errbit.cloudfoundry.com | mongodb-e776e |
+-------------+----+---------+-----------------------------------+---------------+

It also shows connected services - mongodb here. You can now visit your errbit app in your browser. You should see a log in screen, but you can not log in because migrations was not run. Cloud Foundry runs migration only if config/database.yml exists. We don’t have such file because mongoid uses config/mongid.yml file by default. To force running migration just create an empty database.yml file and update app:

$ touch config/database.yml
$ vmc update errbit
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (9K): OK   
Push Status: OK
Stopping Application: OK
Staging Application: OK                                                         
Starting Application: OK

Sometimes update doesn’t success. In that case stopping and starting service may help.

$ vmc stop errbit  
Stopping Application: OK

$ vmc start errbit  
Staging Application: OK                                                         
Starting Application: OK

Alright you should be able to log in to your own error catcher app. Just visit chosen URL (http://martinciu-errbit.cloudfoundry.com/ in my case) and log in with default credentials which are email: errbit@your-app-url.cloudfoundry.com and password: password. You may want to change these default. You can do this by clicking Edit profile button.

Configuration

You can now configure your production app that you want be monitored by Errbit. Errbit is compatible with hoptoad_notifier gem, so if you are familiar with this it should be pretty obvious to you. If you don’t use hoptoad you should add it to your Gemgile

gem "hoptoad_notifier"

and run bundle install command

You can create new app on the homepage, define who should receive notifications and create a config/errbit.rb file from the code provided by Errbit. In my case this file looks like this:

HoptoadNotifier.configure do |config|
  config.api_key = '3aa6c74ccabaf61295c1d10813575705'
  config.host    = 'martinciu-errbit.cloudfoundry.com'
  config.port    = 80
  config.secure  = config.port == 443
end

Unfortunately Errbit overwrites default hoptoad_notifier settings, so you can not use both error catchers at same time. Alright you should now be able to send a test error notification. Just go to you app folder and run:

$ rake hoptoad:test

You should a lot of dumped XML data and a while later you should receive email notification from Errbit. You can also review the test error on your errbit app. And that it! You have up and running your own Hoptoad clone!

Something went wrong?

If something went wrong (it probably will :P) you can find these tools and resources useful: 1. vmc logs errbit 2. vmc files errbit logs 3. vmc help 4. Cloud Foundry Forum 5. Cloud Foundry source code on GitHub 6. Errbit source code on GitHub

Rails 3.1 and Slow Asset Pipeline

tl;dr;

Rails 3.1 Asset Pipeline is not slow! It is your app! If your app became slow after upgrading to Rails 3.1 and you use Mongoid – turn preloading models off. If this won’t help profile your app with rack-perftools_profiler.

Rails 3.1

Rails 3.1 is out for a while. It has a bunch of new features and enhancements and a bit of controversy. One of the new features that I wanted to play with was the asset pipeline. So after Release Candidate 4 was out I decided to upgrade zubibu.com to the newest version.

Upgrade

It is pretty easy to upgrade. You can find detailed instructions on David Rice’s blog post. Some additional fixes are in comments below his post so read them as well. If you want to fully use asset pipeline you also have to modify all urls in your stylesheets from:

background: #ffffff url(images/backend/bg.png) repeat-x 0 0

to:

background: #ffffff url(<%= asset_path "backend/bg.png"%>) repeat-x 0 0

and add .erb extension to all modified CSS files. One good regular expression should be enough for updating all your files.

Horror

I restarted application and then the horror begun. It was impossible to load whole page with all the assts. Some assets returned 500 status code, some load in 30+ seconds. I tried some tricks with linking app/assets/images/ folder to public/images/. It helped a lot, as images was not served by rails, but still CSS and JavaScript files was very slow. If I don’t reload pages by CMD+R I was able to work, but styling pages was almost impossible.
slow assets pipeline

Why is it so slow?

I couldn’t believe that asset pipeline is so slow. Yes, it should be slower that serving static files from disk but it should not be THAT slow. I decided to check what is wrong. I created new rails 3.1 application, added one model with scaffold, one stylesheet and one javascript. I started the application and everything was alright. Assets was loading under 50ms. Then I’ve added more images, stylesheets, and javascripts. About twenty files together. And still everything was running smoothly. We use mongoid as an ORM in zubibu, so I migrated the only model to mongoid. But it still was damn fast! It was fast until I added more models to my test application. After adding 30 models (with relations between them) assets started to load in about 3 seconds each. The models was very simple without any logic – just a few fields and references each. It means that it could be models them self but the fact that there are many models.

perftools.rb

I didn’t want to dig in mongoid source code for ever, so decided to use great profiling tool: perftools.rb and because I need to profile web app I used rack-perftools_profiler middleware. I ran profiler two times: first with 1 model and than with 30 models loaded. Reading profile data is quite hard and, I am not the best in this, but I noticed that when app is running with many models loaded it spends much more time in Mongoid::load_models method which looks like this:

14 def load_models(app)
15   return unless ::Mongoid.preload_models
16   app.config.paths["app/models"].each do |path|
17     Dir.glob("#{path}/**/*.rb").sort.each do |file|
18       load_model(file.gsub("#{path}/" , "").gsub(".rb", ""))
19     end
20   end
21 end

And what is ::Mongoid.preload_models? It is config option turn on by default that reloads all models on each request. According to mongoid documentation you can turn it off if don’t use single collection inheritance in your app. To turn it off simply add following line to your congif.applicaton file:

config.mongoid.preload_models = false

I did it in my application and it works! It is usable again!

Blogging Like a Hacker Using Jekyll, Compass and Foreman

You probably already know how to blog like a hacker using Git and Jekyll It is realy simple but powerfull way of maintaing personal blog. If you put it’s code on the github like Jeff Kreeftmeijer did you can even count on comunity contribution to your own personal blog. How could is that!

If don’t use jekyll for you blog you should definetly reconsider that. If you already do use jekyll you probably know that for developemnt you need to run

$ jekyll --server

to set up simple local server that automatically regenarates static files echa time they are changend. If you also use SASS or Compass for your stylesheets you need to run in second terminal

$ sass --watch input-dir:output-dir

or for Comapss

$ compass watch

That is preaty annoying to run two processes in two separate terminals.

Foreman & Procfile

And this is where Foreman comes with help. Foreman is a process manager for applications with multiple components. It manages Procfile-based applications. We have application with two components so this perfetly fits for our needs. All we need is to add Procfile To make it work install foreman by

$ gem install foreman

and create Procfile under root directory

jekyll:  jekyll --server
comapss: compass watch

To start both processes just type

$ foreman start

and you should see smething similar to:

forman start output

That’s it! Your are a better now!

Enjoy!

Rails 2.2, Bundler, Rack and Pow

Yesterday I have upgraded our production server. I updated rubygems to version 1.8.5 and bundler to 1.1.pre.5. I also updated zubibu.com ‘s staging server by uploading quite a few new gems. One of these actions (or all of them together) broke a few old, low-trafic rails websites. I didn’t investigate what exactly did break them. All broken websites had one thing in common – they were so old that they didn’t use bunlder to manage gems.

Bundler

Most of them was written in rails 2.3, so managing them to user bundler was preaty easy. You can manual on bundler website how to do it and that simply wokrs. But one of the broken webisetes was running Rails 2.2.2. I googled if such old app can use bundler, but didn’t find any answers. So I decided to try it. I started with the inststructions for rails 2.3 app.

I have added this code to the config/boot.rb file right above the line Rails.boot!

class Rails::Boot
  def run
    load_initializer

    Rails::Initializer.class_eval do
      def load_gems
        @bundler_loaded ||= Bundler.require :default, Rails.env
      end
    end

    Rails::Initializer.run(:set_load_path)
  end
end

Then I created config/preinitializer.rb file

begin
  require "rubygems"
  require "bundler"
rescue LoadError
  raise "Could not load the bundler gem. Install it with `gem install bundler`."
end

if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24")
  raise RuntimeError, "Your bundler version is too old for Rails 2.3." +
   "Run `gem install bundler` to upgrade."
end

begin
  # Set up load paths for all bundled gems
  ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
  Bundler.setup
rescue Bundler::GemNotFound
  raise RuntimeError, "Bundler couldn't find some gems." +
    "Did you run `bundle install`?"
end

And created the Gemfile

$ bundle init

I copied there all config.gem directives from confiv/environmet* files and lock the gems at the certain versions as the probably wouldn’t run with old code.

That would be all from gembundler instructions, so I created a gemset for this faling app and run bundle install. When I try to run tests I got this depracation warning:

rake/rdoctask is deprecated.  Use rdoc/task instead (in RDoc 2.4.2+)

To get rid of it just replace replace one line in your Rakefile

# require 'rake/rdoctask'
require 'rdoc/task'

and add rdoc to your Gemfile

#...
gem 'rdoc'

After bundle install all the tests passed. Yay!

Pow & Rack

I run all my rails application using Pow. This one I wanted to run same as others. I just add a symbolic link in my ~./pow folder and visited an .dev url in the browser and I got this message:

If you’re using a version of Rails older than 2.3, you’ll need to upgrade first.

Not good :(. They advised me to upgrade my application but I realy don’t want to do. Before I googled how to upgrade from rails 2.2 to 2.3 I decided to give it a try and just add the cofnig.ru file.

require File.dirname(__FILE__) + '/config/environment'
run ActionController::Dispatcher.new

Then I vited app’s dev url in the browser just to get this message:

MissingSourceFile: no such file to load -- rack

To fix it just add gem 'rack' to your Gemfile. Than all works perfectly! Even my old rails 2.2 app.

tl;dr

1. Bundler works with rails 2.2 app.
2. Pow works with rails 2.2 app even if docs says something else
3. If you want to know how – read the whole thing!

Mounting Grape API Inside Rails Application

Grape is a REST-like API micro-framework for Ruby. It is built to complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily provide APIs. It has built-in support for common conventions such as multiple formats, subdomain/prefix restriction, and versioning. Because grape APIs are Rack applications, it is very easy (in rails 3) and quite easy (in rails 2.3) to mount it in your existing rails application.

API

Let’s start with a simple API. Assuming you have a simple blog application with Post resource and you want to list all posts and show a specific post by ID using API.

#lib/api.rb
module MyApp
  class API < Grape::API
    prefix "api"
 
    resource "posts" do
      get do
        Post.all
      end
 
      get ':id' do
        Post.find(params[:id])
      end
    end
 
  end
end

Rails 3

Because of Rails3 modularity it is very easy to mount any Rack application inside existing application. You only need to add following line to your config/routes.rb file

#config/routes.rb
mount MyApp::API => "/" #API will be available under "/api" url because of setting from MyApp::API line 4

After restartig your application, GET /api/posts should returns all posts, and GET /api/posts/2 should returns post with id=2. Simple as that.

Rails 2.3

If you want to use grape with rails 2.3, things are a little more complicated. We can use the same lib/api.rb file, but we can not mount our API in config/routes.rb. Fortunately, rails 2.3 is actually a rack application, so we can use Rack::Cascade to run api request without touching rails app. But, first things first.

When you are starting rails application by ruby script/server, an new Rack::Builder is being initialized with some middleware and new rails dispatcher:

 83 # rails/lib/commands/server.rb
 84   require RAILS_ROOT + "/config/environment"
 85   inner_app = ActionController::Dispatcher.new
 86 end
 87  
 88 if options[:path].nil?
 89   map_path = "/"
 90 else
 91   ActionController::Base.relative_url_root = options[:path]
 92   map_path = options[:path]
 93 end
 94  
 95 app = Rack::Builder.new {
 96   use Rails::Rack::LogTailer unless options[:detach]
 97   use Rails::Rack::Debugger if options[:debugger]
 98   map map_path do
 99     use Rails::Rack::Static 
100     run inner_app
101   end
102 }.to_app

Then, a server runs app. Any server knows how to run it because app is a valid Rack application. So, why can we run rack app our own? Sure we can! The best way to run is to define it in config.ru file. Rails 2.3 is not shipped with it, so you have to create it by your self. Unless you changed default options your config.ru file should looks like this:

require "config/environment"
 
use Rails::Rack::LogTailer
use Rails::Rack::Static
run ActionController::Dispatcher.new

Now, you can start your appliction by:

$ [bundle exec] rackup

Your application should run like before, except logs my looks a little bit different. Now we will add our API to the application. To do that, we will use Rack::Cascade. Rack::Cascade tries an request on several apps, and returns the first response that is not 404 (or in a list of configurable status codes). We want our API to be as fast and lightweight as possible. That’s why we will add before trying rails application, to avoid all it’s magic when it is not necessary.

require "config/environment"
 
rails_app = Rack::Builder.new do
  use Rails::Rack::LogTailer
  use Rails::Rack::Static
  run ActionController::Dispatcher.new
end
 
run Rack::Cascade.new([
  MyApp::API,
  rails_app
])

Now, routes GET /api/posts should disply all posts, and GET /api/posts/2 should work as expected.

Differences Between Proc.new and Lambda in Ruby

It will be another not very innovative post about a something that probably most Ruby developers already know. Unfortunately I didn’t know about this before, and I think it will be a quite good form of this blog, that I will be posting things that I’ve recently learned. So here is what I’ve learned today.

Proc.new and lambda does almost the same job. They provide a dynamically created inline method. But they are slightly different. What are the differences? There are two (as far as I know at the moment)

1. Acceptance of parameters

Proc.new doesn’t care how many parameter do you provide, when lambda needs exact number of parameters. Example:

pr = Proc.new {|a,b,c| puts a,b,c}
pr.call(1, 2, 3, 4)
# 1
# 2
# 3

…and…

pr = lambda {|a,b,c| puts a,b,c}
pr.call(1, 2, 3, 4)
# ArgumentError: wrong number of arguments (4 for 3)

2. Returning from a proc
return called in Proc.new block returns from enclosing method when return called in lambda block returns from just a block.
Examples:

def my_method
  puts "Starting my_method"
  pr = Proc.new {return}
  pr.call
  puts "Finishing my_method"
end
 
puts "Before my_method"
my_method
puts "After my_method"
# Before my_method
# Starting my_method
# After my_method

but…

def my_method
  puts "Starting my_method"
  pr = lambda {return}
  pr.call
  puts "Finishing my_method"
end
 
puts "Before my_method"
my_method
puts "After my_method"
# Before my_method
# Starting my_method
# Finishing my_method
# After my_method

The other thing that is worth mentioning is that there exist an instruction called proc. What is wired, it works different in ruby 1.8 and in version 1.9. In Ruby 1.8 proc behaviors like lambda when in Ruby 1.9 it works like Proc.new. Because of this, and because of ruumors that proc instruction will be removed in ruby 2.0, I don’t recommend using it in your code.