Rails on Maui

Programming in Paradise

Pry, Ruby, Array#zip, CSV, and the Hash[] Constructor

A couple weeks ago, I wrote a popular article, Pry, Ruby, and Fun With the Hash Constructor demonstrating the usefulness of pry with the Hash bracket constructor. I just ran into a super fun test example of pry that I couldn’t resist sharing!

The Task: Convert CSV File without Headers to Array of Hashes

For example, you want to take a csv file like:

| 1 | Justin | Gordon |
| 2 | Tender | Love   |

And create an array of hashes like this with column headers “id”, “first_name”, “last_name”:

    [0] {
               "id," => "1",
        "first_name" => "Justin",
         "last_name" => "Gordon"
    [1] {
               "id," => "2",
        "first_name" => "Tender",
         "last_name" => "Love"

You’d think that you could just pass the headers to the CSV.parse, but that doesn’t work:

[11] (pry) main: 0> col_headers = %w(id, first_name last_name)
    [0] "id,",
    [1] "first_name",
    [2] "last_name"
[12] (pry) main: 0> csv = CSV.parse(csv_string, headers: col_headers)
(pry) output error: #<NoMethodError: undefined method `table' for #<Object:0x007fdbfc8d5588>>

Rails Gem Upgrading Tips and Strategies

What are the best-practices for upgrading gems to newer versions? What sort of tips and techniques can save time and headaches?

I built this guide based on my real-world experiences over years of gem migrations, including a recent upgrade to Rails 4.1, RSpec 3.0, and Twitter Bootstrap 3.2. There are some more specific examples of errors you might encounter at this article on the Rails on Maui blog: Specific Issues Upgrading Gems to Rails 4.1, RSpec 3, and Twitter Bootstrap 3.2.

Why Update?

Here’s my favorite reasons for keeping gems relatively current:

  1. If you work on several projects, keeping the gems and ruby version consistent makes your coding more productive as you don’t have to keep adjusting for which version is which. Web searches tend to find relatively recent versions first. It’s relatively annoying to be yak shaving issues that turn out to be “oh, that doesn’t work in that older version of Rails”.
  2. Recent versions of gems will have fixes for bugs and security issues, in addition to new features. With popular open source projects, new bugs are quickly discovered and fixed.
  3. Updates are much easier if you stay relatively current. I.e., it’s much easier to update from Rails 4.0 to Rails 4.1 than to go from Rails 3.0 to Rails 4.1.

That being said, recent versions can have new bugs, so it’s best to avoid versions that are unreleased or that haven’t aged at least a few weeks.

Specific Issues Upgrading Gems to Rails 4.1, RSpec 3, and Twitter Bootstrap 3.2

This article describes some tougher issues I faced when upgrading to Rails 4.1, Twitter Bootstrap 3.2 and RSpec 3. This is a companion to my related article on Rails Gem Upgrading Tips and Strategies.

Upgrade Links

If you’re upgrading these specific gems, here’s the must-see upgrade links.

  1. Rails 4.1: A Guide for Upgrading Ruby on Rails.
  2. RSpec 2 to RSpec 3.
  3. Twitter Bootstrap: Migrating to v3.x is essential if you’re going from 2.x to 3.x.

Troubleshooting with RubyMine “Find In Path” and the Debugger

After making the require code changes to address the deprecation errors going to rspec 3, I ran into the below obscure error. This one really stumped me, due to the fact that the stack trace did not give me a specific line causing the error, and when I ran the tests individually, I didn’t see any errors.

Failure/Error: Unable to find matching line from backtrace
PG::ConnectionBad: connection is closed

Here’s the stack trace:

Failure/Error: Unable to find matching line from backtrace
  connection is closed
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/postgresql_adapter.rb:589:in `reset'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/postgresql_adapter.rb:589:in `reconnect!'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract_adapter.rb:377:in `verify!'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:458:in `block in checkout_and_verify'
# .rvm/gems/ruby-2.1.2@bpos/gems/activesupport-4.0.8/lib/active_support/callbacks.rb:373:in `_run__2436983933572130156__checkout__callbacks'
# .rvm/gems/ruby-2.1.2@bpos/gems/activesupport-4.0.8/lib/active_support/callbacks.rb:80:in `run_callbacks'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:457:in `checkout_and_verify'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:358:in `block in checkout'
# .rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:355:in `checkout'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:265:in `block in connection'
# .rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:264:in `connection'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:546:in `retrieve_connection'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_handling.rb:79:in `retrieve_connection'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/connection_handling.rb:53:in `connection'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/fixtures.rb:450:in `create_fixtures'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/fixtures.rb:899:in `load_fixtures'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/fixtures.rb:870:in `setup_fixtures'
# .rvm/gems/ruby-2.1.2@bpos/gems/activerecord-4.0.8/lib/active_record/fixtures.rb:712:in `before_setup'
# .rvm/gems/ruby-2.1.2@bpos/gems/rspec-rails-3.0.2/lib/rspec/rails/adapters.rb:71:in `block (2 levels) in <module:MinitestLifecycleAdapter>'

The error was happening in a test that used resque_spec. After much searching, I began to suspect that some customization or optimization caused the issue.

Fast Tests: Comparing Zeus With Spring on Rails 4.1 and RSpec 3

What’s faster? Zeus with Parallel Tests or Spring, in the context of Rails 4.1, RSpec 3, Capybara 2.4, and PhantomJs?

The bottom line is that both work almost equivalently as fast, and the biggest difference for me concerned compatibility with the parallel_tests gem. Zeus works fine with Parallel Tests, although it makes little difference overall with or without Zeus. Spring doesn’t work with Parallel Tests, but you can work around this issue. So stick with Zeus if it works for you.

And regardless of using Spring or Zeus, the shell scripts provided below called pgr and pgk are essential for quickly listing or killing Zeus, Spring, Rails, or Phantomjs processes!

It’s also worth noting that biggest advantage of using the Zeus or Spring pre-loaders is to save the Rails startup time. On my machine, this is about 3 to 5 seconds. That matters a lot if the test I’m focusing upon only takes a second or two, such as when doing TDD. However, when running a whole test suite taking minutes, 3-5 seconds can get swallowed up by other things, such as rspec-retry, which retries failing capybara tests.

Pry, Ruby, and Fun With the Hash Constructor

I recently had a chance to pair with Justin Searls of TestDouble, and we got to chatting about pry and the odd Hash[] constructor. Here’s a few tips that you might find useful.

The main reason I use pry are:

  1. Testing Ruby syntax.
  2. Documentation and source code browsing.
  3. History support.
  4. cd into the an object to change the context, and ls to list methods of that object.

Pry Configuration

To install pry with rails, place this in your Gemfile

gem 'pry-rails', :group => :development

Then run bundle install. Then run rails console. That gets you the default pry configuration. At the bottom of this article is my ~/.pryrc (gist). Create that file and then run rails c (short for rails console).