– we create awesome web applications

The Rails 4 Way on Leanpub.com

We are proud to announce that our own Vitaly Kushner co-authored the new edition of 'The Rails 4 Way' together with Rails legend Obie Fernandes of Hashrocket fame.

'The Rails 4 Way' is the latest edition of the most comprehensive, authoritative guide to delivering production-quality code with Rails 4.

About half a year ago Vitaly posted a post about how simple it is today to use ruby patches bundled with rvm installation to dramatically reduce big rails app loading times and make your dev environment a much happier place.

Since then Ruby advanced with new patchlevels and there are new patches to use, so let's go over this once again.

First, we start with upgrading the rvm to latest and hopefully greatest

rvm get head

Since Vitaly wrote his post it seems that the railsexpress patch superseded the falcon one. At least that what i got from browsing over the patches repository.

So, next step is to compile our Ruby version with railsexpress patchset applied

rvm install 1.9.3-p392-railsexpress --patch railsexpress

Ok, now for some trivial benchmarking to ensure we made things better and not the other way around. Now, note that the say in the interwebs goes that the bigger your application and amount of gems it has to load the more happy you will be. Also, the usual disclaimer about those performance things, YMMV.

I took a random application from my dev folder. It loads 147 gems. Let's check out some numbers

✗ rvm use 1.9.3
Using /usr/local/rvm/gems/ruby-1.9.3-p392
✗ time rails runner "puts :OK"
OK
rails runner "puts :OK"  16.28s user 1.70s system 98% cpu 18.185 total

✗ rvm use 1.9.3-p392-railsexpress
Using /usr/local/rvm/gems/ruby-1.9.3-p392-railsexpress
✗ time rails runner "puts :OK"
OK
rails runner "puts :OK"  8.56s user 1.22s system 99% cpu 9.820 total

Just to make a comparison to the previous blog post, here are the numbers for the same application with ruby 1.9.3-p327 with falcon patches set:

✗ rvm use 1.9.3-p327-falcon
Using /usr/local/rvm/gems/ruby-1.9.3-p327-falcon
✗ time rails runner "puts :OK"
rails runner "puts :OK"  9.89s user 1.34s system 98% cpu 11.374 total

So, comparing to falcon patches it's not that big of an improvement, but still, another 1.5 seconds win.

And yes, i know that both before and after times are slow. But still, i see a nice around 50% time save on any environment loading. And what i really like is that this improvement demanded the whole 7 minutes of my time.

[Update - 30 Apr 2013] The new, updated and faster version of this blog post covering Ruby 1.9.3 patchelevel 392 and railsexpress patch set.

I knew that there are various Ruby patches available but I've never tried them as I didn't want to waste time for something that I thought I don't really need.

Then I found out that rvm comes bundled with patches ready to be applied, so I'm just a simple command line away from having a patched Ruby. Don't know how I missed that before.

One particular patch that worth trying is falcon. It improves startup time of big Ruby applications. And the bigger your Gemfile is the bigger the improvement.

Try it right now for yourself. It will only take a couple of minutes.

First upgrade rvm to make sure you have the latest

rvm get head

Then the actual Ruby build

rvm install 1.9.3 --patch falcon -n falcon

Note that this command can fail with the following error: Patch 'falcon' not found. The reason is that falcon patch is not yet supported on the latest Ruby patch level, in which case you will need to specify older patch level to make it work.

Find out what patchlevels have falcon support

✗ ls $rvm_path/patches/ruby/1.9.3/*/*falcon* | sort
/usr/local/rvm/patches/ruby/1.9.3/p0/falcon.patch
/usr/local/rvm/patches/ruby/1.9.3/p125/falcon.patch
/usr/local/rvm/patches/ruby/1.9.3/p194/falcon.diff
/usr/local/rvm/patches/ruby/1.9.3/p286/falcon.diff

So latest patch level with falcon support is 286 at the time of this writing.

Install specific patch level with falcon support

rvm install ruby-1.9.3-p286 --patch falcon -n falcon

Congratulations, you now have a patched Ruby installed.

Lets test how much improvement it is. The following is for one of my current projects with about 50 gems:

✗ rvm use default
Using /usr/local/rvm/gems/ruby-1.9.3-p194
✗ time bin/rails runner "puts :OK"
OK
bin/rails runner "puts :OK"  6.47s user 0.60s system 99% cpu 7.106 total
✗ rvm use ruby-1.9.3-p286-falcon
Using /usr/local/rvm/gems/ruby-1.9.3-p286-falcon
✗ time bin/rails runner "puts :OK"
OK
bin/rails runner "puts :OK"  2.79s user 0.52s system 98% cpu 3.354 total

Nice! Startup time decreased from 3.354 to 1.106 seconds. More then twice faster.

I'm going to use this Ruby by default now

rvm use ruby-1.9.3-p286-falcon --default

And while we are on the "lets improve rails startup times" subject, lets do one more change. Add the following to your shell startup file. i.e. ~/.bashrc or ~/.zshrc

export RUBY_HEAP_MIN_SLOTS=1000000
export RUBY_HEAP_FREE_MIN=500000
export RUBY_HEAP_SLOTS_INCREMENT=1000000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_GC_MALLOC_LIMIT=100000000

This will tune Ruby GC settings to be better suited for running big apps (as it seems to be tuned for small Ruby scripts by default).

Lets see how much improvement that is

time bin/rails runner "puts :OK"
OK
bin/rails runner "puts :OK"  2.27s user 0.58s system 98% cpu 2.890 total

Total improvement from 7.106 to 2.890 is almost 60%.

Now, stop fiddling with the environment and go back to creating something great! :)

I recently switched to ruby 1.9.3 as my deafult ruby verison, and suddenly some of my scripts started to fail in funny ways.

One of the latest ones was the script that was supposed to change 'updated' timestamp in a YAML formatted file. Instead of the current date it started to spit out binary strings.

The problem is quite complext but the fix is simple...

First lets see what happens:

In ruby 1.9.2p320:

> require 'yaml'
 => true 
> Time.now.to_s.to_yaml
 => "--- 2012-09-03 22:20:15 +0300\n" 

In ruby 1.9.3p194:

> require 'yaml'
 => true 
> Time.now.to_s.to_yaml
 => "--- !binary |-\n  MjAxMi0wOS0wMyAyMjoyMDozMCArMDMwMA==\n" 

Why did that happen?

This happens because Time.now.to_s returns a non-ascii string

> Time.now.to_s.encoding
 => #<Encoding:ASCII-8BIT>

To remind you, UTF-8 is backwards compatible with the standard 7bit ASCII, as the ASCII is just the subset of UTF8 where the 8th bit is 0;

So to output an 8bit ASCII in UTF-8 a conversion might be required (for example when time format contains regional characters from the upper part of the 8bit ASCII).

It is the same in 1.9.2 but apparently YAML over there knows how to handle it in the case when the string doesn't actually contain any 8bit characters.

In 1.9.3, instead of performing conversions YAML seems to just opting for the 'lets treat it as a binary' handling.

The problem of encodings is complex and "hairy", so we wont go into details here, but in the case when you just need a quick fix like I did you do this:

> YAML::ENGINE.yamler='syck'
 => "syck"
> Time.now.to_s.to_yaml
 => "--- 2012-09-03 22:24:22 +0300\n"

And the problem solved.

Given that module Foo is defined elsewhere what is the difference between the following 2 code snippets?

class Foo::Bar
  ...
end

and this

module Foo
  class Bar
    ...
  end
end

It is actually quite simple. The following code:

# foo.rb
module Foo
  BAR = 123
end

module Foo
  class A
    puts BAR
  end
end

class Foo::B
  puts BAR
end

will output:

123
foo.rb:13:in `': uninitialized constant Foo::B::BAR (NameError)
  from foo.rb:12:in `
'

Simply put, while A has access to the insides of the module's Foo namespace, class B is defined outside of this namespace, only the result of the definition is put as a constant inside Foo.

I most frequently stumble on this when I want to define some common constants in the parent module, just like in the example above. Given that and the fact that the 2nd form doesn't actually require the module to be defined, the 2nd form is probably better and is a safer bet in most cases.

We presented on IGTCloud Ruby On Rails Day today.

Agenda was a bit different this time, not only technical presentations but also a few words about modern approach of building web applications.

Find the slides below.

I was working on tests for blender when I came upon a need to mock or stub a back-tick operator e.g.:

`shell command`

Apparently this is just a shortcut for calling Kernel method :`.

The OPEN 2010 conference was very well organized and had many interesting talks.

We are giving 4 out of 20 sessions at Open 2010, an Israeli open source conference.

I just recently reinstalled my MacBook Pro, this time with Snow Leopard.

So I'm again going through various installation problems I already forgot about from few years back when I installed Leopard.

Anyway, just had to hunt down a problem with mysql gem installation on Snow Leopard.

A few days ago I gave a presentation about Ruby for Sayeret Lambda discussion group.

The title was "Ruby is an acceptable lisp" but the message is better served by "Ruby is Better then Lisp ... sometimes" :)

About a week ago about 15 people were gathered in People and Computers offices thanks to Raphael Fogel.

I've just read "Do You Believe In Magic?" and the following quote resonated particularly well:

"It's not magic. There is no magic involved. It's just, if you never learnt Lisp, then you never learned to program, and Ruby's power is exposing a deficiency in your skills."

Mephisto commenting system is... how do i put it ... outdated :)

And we wanted something more engaging for our blog. Looking around the web we found that Disqus was used all over the place, so we decided to integrate it into our blog instead of the native comments system.

Wouldn't it be cool if you could just require "http://my-host/my-lib.rb" in ruby?

Now You Can! Using our "http_require" gem! :-)

RRDtool is the OpenSource industry standard, high performance data logging and graphing system for time series data. Use it to write your custom monitoring shell scripts or create whole applications using its Perl, Python, Ruby, TCL or PHP bindings.

Let's run it with Ruby on Leopard.

sudo port install rrdtool

Default ports installation comes without ruby bindings.

Thanks a lot to Amit Hurvitz for providing a file of Virtual Disk Image (VDI) of VirtualBox, containing an up and running JRuby on Rails on Glassfish with Mysql. Image also contains some examples (actually solutions to the code camp exercises), all running on top of an OpenSolaris guest OS (can be run on many host systems).

Grab the image ~1.5GB archive.

Grab the exercises ~9.7MB archive.

We participated in JRuby on Rails with GlassFish Code Camp hosted by Sun Microsystems Inc. I was speaking about the framework in general trying to infect Java developers with Ruby On Rails. Slides are available.

Amit Hurvitz gave exciting presentation about GlassFish and short introduction into DTrace. Find out more details about the Code Camp.

I was the last person in our company working with ERB to render templates. While all the rest switched to HAML. At the beginning it was quite hard for me to read HAML comparing to ERB. HAML looked for me like some completely alien thing with weird percent marks all over the place and the significant whitespace never did it for me. On the other hand ERB felt like warm home after years we spent together.

Until I did the switch.

Recently we looked for video transcoding/hosting solution to use in one of our client's projects.

The best thing we've found is Panda. It runs on Amazon stack of services including ec2, s3, and simpledb.

Using amazon has many advantages. no contracts, pay as you go, easy and fast scaling in case your site explodes :)

Unfortunately the image that is refered in the Getting Started (ami-05d7336c) is not safe for production - it has openssh version with a serious security bug, but don't worry, we will explain how to fix it.

In the process of installing Mephisto I've got a problem with image_science gem.

It installed OK but when trying to require it the was a problem with RubyInline compilation:

We really like Debian and we usually use the current "stable" distribution for our production servers.

It all works great with one little problem: if you need very current soft it is probably not in the 'stable' yet.

The current Debian stable ("etch") includes rubygems 0.9.0-5 which is way too old.

We needed to upgrade to at least 1.2.

Once again I’ve hit a problem of installing gems on a machine with very little memory.

On one of our projects we needed to do some caching for an action with an expensive db query. Fragment caching took care of the rendering but we needed a way to skip the db if we have a cache hit. And checking for an existence of the fragment file in the controller just didn’t seem right.