ASCII Thoughts

Using Pry in production (part 1)

If you don't know about Pry yet, you're missing out. It's a replacement REPL for Ruby with tons of features and many plugins, which makes it a perfect replacement for IRB, and as a result, for the standard Rails console.

A little while ago, the fine folks at Bugsnag wrote an article about their usage of Pry in production. I've been a Pry convert for quite some time as well, so today I'd like to share my own tips and tricks.

Running Pry

I think the Bugsnag article nails it pretty well, though I tweak some of the steps:

Configure Pry

Since we are using a dedicated machine, we can have a shared pryrc for everyone that offers some Rails goodies. We are not using pry-rails, so we also need some of the code in ~/.pryrc to do the Rails initialization:

# ~/.pryrc
# MISSING

Play

The first benefit of using Pry is that you get an actual editor for your code. I tend to do a lot of support related tasks, and so I often need to run one off snippets of code. They are slightly more complicated than a one-liner, but at the same time quite straight forward to write and modify. So my usual workflow is this:

PRODUCTION [1] pry(main)> def find_ips; end
PRODUCTION [1] pry(main)> edit find_ips

Since Pry is configured with vim as the default editor, this drops me in vim where I can start writing my code:

require "set"

# Check all the IP addresses used by one user
def find_ips
  list = Set.new
  user = User.find 1234
  user.comments.each {|comment| list << comment.ip}
  list.each {|ip| puts ip}
end

The code is simple, but being able to work with it in a real editor is a big improvement. We can now run it, make adjustments, and iterate until we get it just right:

PRODUCTION [1] pry(main)> find_ips
X.X.X.X
X.X.X.X
X.X.X.X

PRODUCTION [1] pry(main)> edit find_ips
# do some changes

PRODUCTION [1] pry(main)> find_ips
X.X.X.X on Feb 1st, 2014 at 8:14:45 AM
X.X.X.X on Mar 2nd, 2014 at 10:01:32 PM
[...]

The other nice thing is that it makes it a lot easier to extract useful code. As I try to solve a particular problem, or extract data, I will often end up with a method 10 to 20 lines long that solves a particular support use case. If I want to save it for later, or integrate it into the main codebase, I can simply edit it again, and save it to a safe location from vim, or copy/paste it somewhere else. This would be a lot harder if all I had was a bunch of one-liners that only existed in the history of my session.

Patch

One of the most useful feature of Pry is it's ability to easily monkeypatch existing code. Let's say that we have a job that generates a CSV export of some reporting data. The export is great and all customers love it, but this one customer asked you to add another column to it. They have a somewhat narrow use case, and including the column for all customers would not necessarily be an improvement, so you decide to simply run the report once with this extra column, just for them. With Pry, this is super easy!

First, we take a look at the CSV export itself:

PRODUCTION [1] pry(main)> show-source Report#generate_csv

def generate_csv
  [...]
  documents.each {|doc| csv << doc.csv}
  [...]
end

So we know that we need to modify the Document#csv method. It's a simple method that returns an array. We are going to patch the method: the modification will only exist within our Pry session and won't be written on disk. To do that, we use edit -p instead of the standard edit:

PRODUCTION [1] pry(main)> edit Document#csv -p

Add the extra data:

def csv
  [ title,
    content,
    created_at,
    updated_at,
    custom_data ] # LINE ADDED
end

We can now generate the report for this customer, without affecting anyone else:

PRODUCTION [1] pry(main)> Report.find(1234).generate_csv

And we're done!

Conclusion

Pry is a perfect replacement for IRB, and can greatly improve your life when working on production applications. Just for the ability to edit code in vim, Pry is absolutely worth it. I definitely recommend spending some time installing it, configuring it, and getting it working on your application.

And if you've never used Pry before, take a look at this great talk: Ruby Conf 2013 - REPL driven development with Pry by Conrad Irwin. It will make you an instant convert.

That's it for today, cheers!