– we create awesome web applications

Stop using strftime. Seriously. At least if you are using Rails that is.

Rails, or rather, its I18N dependency, has a much better alternative I18n.l. The great thing about it is that you provide the name/kind of the format that you want separately of the format itself, so that you can, for example, change it completely for the whole application, or for a different locale.

The usage is quite simple. Instead of

Time.now.strftime('%Y-%m-%d %H:%M:%S')

You can do instead:

I18n.l Time.now, format: :myformat

with the myformat format defined in a locale file, say config/locale/time_formats.en.yml:

en:
  time:
    formats:
      myformat: '%Y-%m-%d %H:%M;%s'

The format string supports all the same format options as strftime, so conversion of your existing strftime code should be completely trivial.

It is important to pass a Symbol to the :format option of I18n.l, or it will try to interpret it as the format itself, and not its 'name' in the localization file.

Note: I18n.l has an alias I18n.localize, feel free to use it if you like to type.

When you are inside of a Rails view, you have another shortcut:

= l Time.now, format: :myformat

This is not all, yet...

It works for dates to:

I18n.l Date.today, format: :myformat

Event though it uses the same format name, it will use a different localisation key:

en:
  date:
    formats:
      myformat: '%Y-%m-%d'

Of course myformat is not such a great name for a format name ;). In a real application I would use something like compact, full, connfig, etc.

A couple of formats,:short, and :long are already provided, but I wouldn't rely on them and I suggest you define by yourself any time/date format that you intend to use inside of your application.

I recently had an interesting bug that I want to share.

We had an age method in the User model, that was implemented like this:

def age
  return unless birthday
  now = Time.now.utc.to_date
  now.year - birthday.year - (birthday.to_date.change(year: now.year) > now ? 1 : 0)
end

And the following test for it:

describe :age do
  it 'should calculate age on exact date' do
    user = record(birthday: '2000-10-10')
    Timecop.freeze(Date.parse('2010-10-10')) do
      user.age.should == 10
    end
  end

  it 'should calculate age on next date' do
    user = record(birthday: '2000-10-10')
    Timecop.freeze(Date.parse('2010-10-11')) do
      user.age.should == 10
    end
  end

  it 'should calculate age on prev date' do
    user = record(birthday: '2000-10-10')
    Timecop.freeze(Date.parse('2010-10-9')) do
      user.age.should == 9
    end
  end
end

Suddenly, on 2013-07-14, I received a Circleci email that my last commit broke the specs. While investigating I found out that it failed in a place completely unrelated to my latest changes. It failed with an ArgumentError: invalid date. WTF?!

Investigating I found that we had a typo in one of our fixtures, that went like this:

triton:
  name: Triton
  birthday: <%= 501.days.ago %>
  ...

Notice the days instead of years that were ment to be used. And 501 days before 2013-07-14 is 2012-02-29, a leap year extra day, oops ;)

The age implementation tried to do .change(year: 1) to 2012-02-29 which produced an invalid date 2013-02-29. Apparently Date#change wasn't smart enough to take care of that:

> d = Date.parse('2012-02-29')
=> Wed, 29 Feb 2012
> d.change(year: 1)
ArgumentError: invalid date

I changed tirton's age to 501 years, and added the following test:

it 'should not fail when birthdate is on feb-29' do
  user = record(birthday: '2012-02-29')
  Timecop.freeze(Date.parse('2013-05-01')) do
    user.age.should == 1
  end
end

and fixed the implementation to be like so:

def age
  return unless birthday
  now = Time.now.utc.to_date
  diff = now.year - birthday.year
  diff - (diff.years.since(birthday) > now ? 1 : 0)
end

ActiveSupport's Date#since is smarter then #change and handles invalid dates properly:

> d = Date.parse('2012-02-29')
=> Wed, 29 Feb 2012
> 1.year.since(d)
=> Thu, 28 Feb 2013

Also note that there will be no problem with user fixtures on Feb-29 of the next leap year 2016-02-29. The x.years.ago that is used for birthdays will work just fine.

The June 2013 DevCon event took place on June 20. We sponsored the event, as we always do. Also Vitaly gave an overview talk on RubyMotion.

Check out the talk

The are multiple ways of configuring your Rails application for different environments (e.g. staging, production, etc). One of the popular ones is through environment variables. For example Heroku uses this type of configuration extensively.

One of the benefits of it is that configuration values are never stored in the source control system, which improves security (for sensitive configuration parameters) and also makes it easier to try different configuration setups w/o changing the sources or re-deploying the application.

On the other hand writing (ENV['PRIMARY_DOMAIN'] || "myapp.com") every time you need your domain string becomes cumbersome pretty fast, not to mention duplication and having the default repeated all over the place.

A competent programmer will of course only do this once, and re-use the value everywhere. Something like this:

PRIMARY_DOMAIN = ENV['PRIMARY_DOMAIN'].presence || 'myapp.com'
S3_BUCKET = ENV['S3_BUCKET'] || raise 'missing S3_BUCKET'
ORDER_EXPIRATION_DAYS = (ENV['ORDER_EXPIRATION_DAYS'].presence || 1).to_i

But it quickly becomes complicated, and again, quite a bit of similarly looking code that begs to be refactored out.

constfig is something I extracted from a couple of my latest projects. It allows you to do just that, have a configuration parameters stored in constants with values coming from environment variables and ability to provide defaults or have required parameters (i.e. fail if missing).

I just released version 0.0.1 of constfig to rubygems. Sources are of course on github.

Installation

Add this line to your application's Gemfile:

gem 'constfig'

And then execute:

$ bundle

Or install it yourself as:

$ gem install constfig

Usage

There is only one function provided by the gem: define_config.

With a default (optional variable)

You can call it with a default, like this:

define_config :DEFAULT_DOMAIN, "astrails.com"

In which case it will first look if ENV['DEFAULT_DOMAIN'] is available, and if not will use the 'astrails.com'. A constant DEFAULT_DOMAIN will be defined.

Without a default (required variable)

Or you can call it without the default:

define_config :DEFAULT_DOMAIN

In which case it will raise exception Constfig::Undefined if ENV['DEFAULT_DOMAIN'] is not available.

Variable type

One last thing. Non-string variables are supported. If you provide a non-string default (boolean, integer, float or symbol), the value that is coming from ENV will be converted to the same type (using to_i, to_f, and to_symbol). For the true/false types "true", "TRUE", and "1" will be treated as true, anything else will be treated as false.

In the case of required variables, you can supply a Class in place of the default, and it will be used for the type conversion. Like this:

define_config :EXPIRATION_DAYS, Fixnum

For boolean variables you can supply either TrueClass, or FalseClass.

Existing constants

This gem will not re-define existing constants, which can be used to define defaults for non-production environments.

Rails on Heroku

There is one caveat with Rails on Heroku. By default Heroku doesn't provide environment variables to your application during the rake assets:precompile stage of slug compilation. If you don't take care of it your application will fail to compile its assets and might fail to work in production. To take care of it you can either use Heroku Labs user-env-compile option, or (and this is what I'd recommend) you can use development defaults during assets:precompile.

For example in Rails you con do this:

if Rails.env.development? || Rails.env.test? || ARGV.join =~ /assets:precompile/
  DEFAULT_DOMAIN = 'myapp.dev'
end

define_config :DEFAULT_DOMAIN

In development and test environments it will use 'myapp.dev' ad PRIMARY_DOMAIN, but in production and staging environment it will fail unless PRIMARY_DOMAIN is provided by environment.

NOTE: make sure those configuration variables are not actually used for asset compilation. If they are, I'd go with user-env-compile.

Managing environment

You can use the dotenv gem to manage your ENV.

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.

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.

I recently switched to ruby 1.9.3 as my deafult ruby verison, and suddenly some of my scripts started to fail in some 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...

Given that module Foo is defined elsewhere what is the difference between this snippet:

class Foo::Bar
  ...
end

and this:

module Foo
  class Bar
    ...
  end
end

Answer inside ;)

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.