Friday, May 30, 2014

"Try not. Do... or do not. There is no try."

At first glance, the try method in Rails is great. It's a quick way to do nil checks in a chain to get at associations and attributes. I've avoided it when I can, partly out of habit and partly because its syntax can be slightly less readable. However, there is another reason to not use try: it can also hide seriously time-wasting bugs caused by misnamed methods, e.g.:

$ rails c
2.1.1 :001 > if ''.try(:incorrectly_named_method)
2.1.1 :002?>   # assume method returned nil
2.1.1 :003 > end
 => nil 
2.1.1 :004 > unless ''.incorrectly_named_method
2.1.1 :005?>   # assume method returned nil
2.1.1 :006 > end
NoMethodError: undefined method `incorrectly_named_method' for "":String
 from (irb):4
 from bin/rails:4:in `require'
 from bin/rails:4:in `

That undefined method error on execution can really help. If you avoid it, then if the method name changes, or if you had typed the method name incorrectly, you may not find out about it quickly.

Why would you use try? A few good reasons for using try might be: (1) you are absolutely sure the method name is correct and will not change, and/or (2) you might have used defined? to check that the method existed before attempting to call the method.

Remember that Yoda said, "Try not. Do... or do not. There is no try."

Tuesday, April 15, 2014

Temporarily Force a No-arg Initializer in Ruby

How to temporarily bypass a Ruby class initializer, which you shouldn't do unless you really just need access to the instance and don't require any setup that happens in the initializer:

def force_class_instance(klass)
  result = nil
  if klass.instance_method(:initialize).parameters.any? {|ar|ar[0] == :req}
    klass.class_eval 'alias_method :orig_initialize, :initialize; def initialize; end'
    result =
    warn_level = $VERBOSE
    $VERBOSE = nil
    klass.class_eval 'remove_method :initialize; alias_method :initialize, :orig_initialize; remove_method :orig_initialize'
    $VERBOSE = warn_level
    result =

Now just use force_class_instance(YourClass) to get an instance.

The $VERBOSE setting is to avoid "(eval):1: warning: removing `initialize' may cause serious problems" showing up in the log.

Tuesday, March 18, 2014

Extract the Version of Bundler, Chef, Ruby, etc. for CI

RVM and rbenv can use the .ruby-version file to define the Ruby version to use for your application. What about extracting the versions for Bundler and Chef?

If your application doesn't need to know anything about Chef, but you want your CI build/tests for that application to use your Chef bootstrapping process to set up your VM, maybe in your Chef repo where you keep your recipes, etc., your Chef Gemfile might look like:

chef_version =

gem 'chef', chef_version

And, let's say that you have a Chef bootstrap script that needs to install Bundler prior to doing bundle install:

gem install bundler --version=`cat .bundler-version`
bundle install

Now put the Chef version in .chef-version and the Bundler version in .bundler-version, e.g. if a version is 1.2.3, then the file would only contain:


Your application's repo just has .ruby-version and the rest of the application, but after you clone it and change to that directory in CI, you could do the following to grab and use those new version files from the Chef git repo. More about git archive here:

rbenv install `cat .ruby-version` || true
rbenv local
git archive --format=tar \
  --remote=your_chef_git_repo_uri \
  HEAD: .chef-version .bundler-version \
  | tar -x
gem install bundler --version=`cat .bundler-version`
gem install chef --version=`cat .chef-version`

That installs ruby if it isn't there (need || true so won't fail if already installed), uses it, just gets .chef-version and .bundler-version from another git repo, and then installs bundler, then chef, and you are ready to start bootstrapping. If you are using RVM like I do in development (this is the long version- you might not need all of this):

if test -f ~/.rvm/scripts/rvm; then
    [ "$(type -t rvm)" = "function" ] \
       || source ~/.rvm/scripts/rvm
rvm get stable
rvm install `cat .ruby-version` || true
# if using gemset, specify that too, and --create
rvm use `cat .ruby-version`
git archive --format=tar \
  --remote=your_chef_git_repo_uri \
  HEAD: .chef-version .bundler-version \
  | tar -x
gem install bundler --version=`cat .bundler-version`
gem install chef --version=`cat .chef-version`

It is a bit dirty. Docker may be a better choice now for getting setup quickly, but if you use chef and other shell scripts, etc., then extracting version numbers might help.

Monday, March 17, 2014

Using Bullet with MiniTest to Identify N+1 Queries

The Bullet gem can be helpful when used on an on-demand basis to identify some n+1 query problems in code called by your integration tests. Although Tommy noticed that Bullet gives a false notification (see #148 for status) when using empty? on a relation that would trigger a query unless there is an includes, it identified some n+1 queries effectively.

In your test group in Gemfile:

# this example is just for testing,
# but it might be helpful in development as well
group :test do
  # ...
  gem 'bullet', '~> 4.8.0'

Then at command-line:

bundle install

In test_helper, we require a file that contains something similar to the following:

  Bullet.enable = true
  # it is set this way by default, but being explicit
  Bullet.raise = false

  require 'minitest/unit'
  module MiniTestUsesBullet
    def before_setup
      super if defined?(super)

    def after_teardown
      super if defined?(super)
      if passed?
        # format however you want
        raise "Bullet failed: #{Bullet.warnings.inspect}" if Bullet.warnings.present?

  class MiniTest::Unit::TestCase
    include MiniTestUsesBullet

Then prefix BULLET=1 in command line when running a test or all tests. Bullet docs note similar, but they use rspec and they leave it kind of up-in-the-air of what to use. We originally tried Bullet.raise=true, but Tommy noticed that hides valid ActiveRecord errors because the Bullet (4.8.0 at least) raises at the end of the Rack request handling. So, instead you need to only fail if the test passed and if there are warnings. As Tommy noted, since it is Rack based, you might only add this to your integration tests (not controller tests, etc.) vs. MiniTest::Unit::TestCase, and he said this works for better format:

raise'\n') unless warnings.values.empty?

Wednesday, March 5, 2014

Using GC vs. ObjectSpace for Counting Arrays, etc. Created in Ruby

One way to use ObjectSpace to diff the number of Ruby arrays created is:

def log_objectspace_object_count_delta(key)
  orig = ObjectSpace.count_objects[key]
  puts "#{ObjectSpace.count_objects[key] - orig} ObjectSpace objects created"

Which would let you specify the key, in this case :T_ARRAY, to find the delta in object count:

2.1.0p0 :006 > log_objectspace_object_count_delta :T_ARRAY do; nil; end
0 ObjectSpace objects created
 => nil 
2.1.0p0 :007 > log_objectspace_object_count_delta :T_ARRAY do; []; end
1 ObjectSpace objects created
 => nil 

GC has a nice little stat method that might also help, e.g.:

def log_gc_objects_allocated_delta
  orig = GC.stat(:total_allocated_object)
  puts "#{GC.stat(:total_allocated_object) - orig} objects allocated"

2.1.0p0 :006 > log_gc_objects_allocated_delta do; nil; end
0 objects allocated
 => nil 
2.1.0p0 :007 > log_gc_objects_allocated_delta do; []; end
1 objects allocated
 => nil 

We are intentionally not taking into account :total_freed_object there, because our goal is to just see how many objects were allocated.

And, please note that, according to the Ruby 2.1 API: "The contents of the hash are implementation specific and may be changed in the future. This method is only expected to work on C Ruby."

Friday, February 21, 2014

Puts'ing/Logging all ActiveRecord Callbacks in All Models in Rails

Sometimes it is helpful in test_helper or wherever to start puts'ing/logging all (or some) ActiveRecord callbacks.

The following loads all models in a Rails app (if it can) and adds callbacks to puts that they were called. Not perfect, but works enough for this example. Try putting this into an initializer, e.g. config/initializers/001_log_callbacks.rb:

# Log all callbacks
Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
  name = File.basename(filename, '.rb')
    model = name.camelize.constantize
    ActiveRecord::Callbacks::CALLBACKS.each do |callback|
      if callback.to_s.start_with?('around_')
        model.class_eval "#{callback} do |*args, &prc|; puts \"#{model}(\#{id}).#{callback} start\";*args) if prc; puts \"#{model}(\#{id}).#{callback} end\" end"
        model.class_eval "#{callback} do; puts \"#{model}(\#{id}).#{callback}\" end"

Note that this is loading all models directly under app/models/ so you might not want to use this for more than temporary debugging.

Wednesday, February 19, 2014

Ruby's ObjectSpace and Diffy to Diagnose Unknown Object Changes

Ever diff'd ObjectSpace in Ruby/Rails?

As an example, I had a situation where I thought maybe I wasn't saving a record, and because it was a complex structure, the simplest thing seemed to be to try this:

unsaved = ObjectSpace.each_object(ActiveRecord::Base)
raise "expected all models in memory to be saved, but the following had changes:\n#{unsaved.join("\n")}" if unsaved.size > 0

...but that didn't show anything.

Since none of the model instances where changed- I thought it would be interesting to reload every ActiveModel::Base instance, then do a before and after diff of model instances in ObjectSpace. That way in scanning the diff, I might happen to see difference between model instances without having to deep dive through a bunch of associations, comparing objects.

Seems somewhat random, but it was interesting.

First add Diffy to your Gemfile and bundle install. Then after doing some queries/updates, try this:

# Note: this is a good way to waste memory and create
# some very long strings

# First, let's garbage collect. Then inspect all
# ActiveRecord::Base instances in ObjectSpace, sort
# those inspection strings, and then split them
# into lines for Diffy.
a = ObjectSpace.each_object(ActiveRecord::Base)",", ",\n").gsub(">\",", ">\",\n")

# Now, let's reload all of them, just for kicks. :)
ObjectSpace.each_object(ActiveRecord::Base) {|m|m.reload}

# Do what we did before.
# part of ObjectSpace
b = ObjectSpace.each_object(ActiveRecord::Base)",", ",\n").gsub(">\",", ">\",\n")

# Diff it!
if a != b
   puts "Changes: #{, b).to_s}"