I love each, but I have a problem with it. What happens when you have an empty collection?

If you call [].each, nothing will happen and [] will be returned. Sometimes, that’s what you want. But more often, especially when you’re building UI, you’ll want to handle empty lists in a special way. For example, I usually want to show a different message when I don’t have any data.

But since [].each returns [], not nil, you’re stuck writing something like this:

app/views/users/index.html.erb
1
2
3
4
5
6
7
<% if @users.empty? -%>
  <p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>
<% else -%>
  <% @users.each do |user| -%>
      <p><%= user.name %></p>
  <% end -%>
<% end -%>

That works, but it feels awkward. I’d rather say, “Do this thing to each item in this collection, unless there’s nothing in it, in which case do this other thing entirely.” I want something like each, with an “or else.”

Rendering Rails Collections

Inside your views, Rails can help. It’s great at rendering collections of things:

app/views/users/index.html.erb
1
<%= render @users %>
app/views/users/_user.html.erb
1
<p><%= user.name %></p>

When render is passed @users, it renders _user.html.erb once for each user inside @users. You can skip the each entirely.

As a bonus, if @users is empty, render returns nil, just like we want! So you can write this, and get the same output as the original version:

app/views/users/index.html.erb
1
<%= render(@users) || render('empty') %>
app/views/users/_user.html.erb
1
<p><%= user.name %></p>
app/views/users/_empty.html.erb
1
<p>You don't have any users. <%= link_to "Add one!", new_user_path %></p>

It’s a lot more direct, once you understand Rails’ conventions.

What about outside of a view?

If you follow Rails, render with a collection is a fast, powerful way to render collections of objects.

But sometimes you won’t want to deal with an extra partial to render each item. Or render won’t support your design. Or you won’t even be inside a view.

The best solution I’ve found so far is presence.

list.presence is the same as:

1
2
3
4
5
if list.present?
  list
else
  nil
end

That is, you’ll get the list back if it has anything in it, and nil if it’s empty.

With presence, you could write:

1
2
3
@users.each do |user|
  puts user.name
end.presence || puts("You don't have any users.")

This prints each name if there are users in @users, or You don't have any users otherwise.

Still, I could do without the presence. It feels like a hack, because it is one. If it was supported, something like this might be better:

1
2
3
@users.each do |user|
  puts user.name
end || puts("You don't have any users.")

or the Smalltalk-ish:

1
2
3
@users.each(if_empty: lambda { puts "You don't have any users." }) do |user|
  puts user.name
end

or even (gasp!):

1
2
3
4
5
for user in @users
  puts user.name
else
  puts "You don't have any users."
end

For now, though, I usually just go with presence or the basic if blank?; else each pattern.

Which do you think is better? How do you handle empty lists? Have you found a better way? If so, tell me about it!

There are a lot of ways to launch a Ruby or Rails console: irb, bundle exec irb, bundle console, and rails console are some of the most common. They seem similar, but they each work a little bit differently.

If you don’t know what those differences are, you’ll have some problems. Maybe you won’t be able to get your ActiveRecord models connected to the database. Or you’ll require a file and get the wrong version. Or a library you thought would be avaliable, wasn’t.

How do you make sure you’re using the right console at the right time?

Bundler vs non-Bundler

irb is just a plain Ruby console. It doesn’t care about your Gemfile. It doesn’t load anything but the core Ruby libraries. Anything else you want, you have to require.

If you install a gem using gem install, you can require it inside irb. If you used bundle install, you might be able to require it, depending on where Bundler put it. (Bundler will sometimes put gems outside of Ruby’s gem path, if you run something like bundle install --path or bundle install --deployment).

Since irb ignores your Gemfile, the versions inside your Gemfile.lock don’t matter. irb will load the newest version of a gem it can find:

1
2
3
4
5
6
7
8
9
10
11
12
13
~/Source/testapps/consoles[master *] jweiss$ gem list rails

*** LOCAL GEMS ***
rails (4.2.0.beta2, 4.2.0.beta1, 4.1.5, 4.1.1)

~/Source/testapps/consoles jweiss$ cat Gemfile | grep rails
gem 'rails', '4.1.5'

~/Source/testapps/consoles jweiss$ irb
irb(main):001:0> require 'rails'
=> true
irb(main):002:0> Rails.version
=> "4.2.0.beta2"

This can cause really weird problems with your code, if you’re not expecting it.

irb is great if you’re messing with core Ruby files. It’s fast, and doesn’t need any setup.

But if you want to use your Gemfile when you run a console, run bundle exec irb instead. The bundle exec allows irb to load the gems that Bundler knows about, and only the gems Bundler knows about:

1
2
3
4
5
~/Source/testapps/consoles jweiss$ bundle exec irb
irb(main):001:0> require 'rails'
=> true
irb(main):002:0> Rails.version
=> "4.1.5"

We got exactly the Rails version we were looking for.

bundler/setup vs Bundler.require

When would you run bundle console instead of bundle exec irb?

bundle exec irb sets things up so you can only require the gems in your Gemfile.lock.

bundle console goes one step further. When you run bundle console, you don’t even need to require the gems in your Gemfile. They’re already required for you:

1
2
3
4
5
6
7
8
9
~/Source/testapps/consoles jweiss$ bundle exec irb
irb(main):001:0> Rails.version
NameError: uninitialized constant Rails
  from (irb):1
  from /usr/local/bin/irb:11:in `<main>'

~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.version
=> "4.1.5"

You could also get this behavior if you called Bundler.require inside your bundle exec irb console. Any gem in your Gemfile that isn’t marked require: false will be automatically required, and you’ll be able to use it without any extra work. When you’re working on projects with a Gemfile, that’s incredibly convenient.

Accessing Rails

There’s still one difference to think about: bundle console and rails console.

1
2
3
4
5
6
7
8
~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.application
=> nil

~/Source/testapps/consoles jweiss$ rails console
Loading development environment (Rails 4.1.5)
irb(main):001:0> Rails.application
=> #<Consoles::Application:0x007f8db4d5ab30 @_all_autoload_paths=["/Users/jweiss...

bundle console just requires a bunch of gems. rails console requires those gems, but it will also load your entire Rails environment, set up autoloading, initialize your application, and give you a full Rails environment to play around in.

You can get something like the Rails console from bundle console if you require config/environment.rb:

1
2
3
4
5
6
7
~/Source/testapps/consoles jweiss$ bundle console
irb(main):001:0> Rails.application
=> nil
irb(main):002:0> require_relative 'config/environment.rb'
=> true
irb(main):003:0> Rails.application
=> #<Consoles::Application:0x007fd264f0b7c8 @_all_autoload_paths=["/Users/jweiss...

Each one, just a little more complicated

So, to recap:

  • irb is the basic Ruby console. It ignores your Gemfile, and only core Ruby classes are accessible without require-ing them. It can’t easily load gems that Bundler installs outside of RubyGems’ load path.

  • bundle exec irb is like irb, if you also required bundler/setup. You can only easily require gems that are in your Gemfile.lock, but you can load those gems no matter where Bundler put them.

  • bundle console is like bundle exec irb, if you also called Bundler.require. All of the gems in your Gemfile, except the ones marked require: false, can be used without requiring them. It’s really convenient when you’re writing your own gems, or working on non-Rails code.

  • rails console is like running bundle console inside a Rails app, if you also required config/environment.rb. You can play with your entire Rails app, autoloads and database connections work, and everything’s hooked up the way you’d expect. If you’re working in a Rails app, this is the most helpful kind of console.

There aren’t too many differences between these consoles. And while most of those differences won’t be too big (Oh, this file isn’t required? Better require it!), others will be totally infuriating if you don’t know what’s going on. (WHY IS THIS LOADING THE WRONG VERSION OF RAKE AGAIN!?)

But if you know the idea behind each of these consoles, you’ll be able to use the right kind of console at the right time. And all the libraries you need will be close by when you need them.

Have you ever wanted to pass a method to a function that only takes a block? Or figure out which of your object’s superclasses broke the method you’re trying to call?

Those things are easy to do with the method method. Use it well, and you can learn about your dependencies, save yourself hours of debugging, and get your code to the places it needs to be.

Methods as easy as lambdas

Lots of Ruby methods take blocks or lambdas. But you can’t directly pass a method to another method, the way you would with a lambda. You have to use method first:

1
2
3
4
irb(main):001:0> sin_method = Math.method(:sin)
=> #<Method: Math.sin>
irb(main):002:0> (1..10).map(&sin_method)
=> [0.8414709848078965, 0.9092974268256817, 0.1411200080598672, -0.7568024953079282, -0.9589242746631385, -0.27941549819892586, 0.6569865987187891, 0.9893582466233818, 0.4121184852417566, -0.5440211108893699]

So, what’s happening here?

The first line turns the method Math.sin into a Method object. Just like lambdas, Method objects respond to call. Method objects respond to to_proc (Thanks, Benoit). So they can be used in the same places you’d use a lambda:

1
2
3
4
irb(main):004:0> sin_method = -> (x) { Math.sin(x) }
=> #<Proc:0x007fe9f90a9bd8@(irb):4 (lambda)>
irb(main):005:0> (1..10).map(&sin_method)
=> [0.8414709848078965, 0.9092974268256817, 0.1411200080598672, -0.7568024953079282, -0.9589242746631385, -0.27941549819892586, 0.6569865987187891, 0.9893582466233818, 0.4121184852417566, -0.5440211108893699]

Take a look at the first line again. This code, using a lambda, works the same way as the earlier code, using method.

Depending on how you’ve written your code, getting ahold of a Method object can be a lot easier than wrapping it in a lambda. So when you need a lambda and all you have is a method, remember the method method.

Where did that method come from?

You just called a method on your object, and it does something you didn’t expect. Maybe someone overrode it or monkey-patched it. How do you figure this out?

You could dig through the source code for a few hours. But Method has two methods that can speed things up.

To figure out which class defined the method you’re calling, use owner:

1
2
irb(main):003:0> Task.new.method(:valid?).owner
=> ActiveRecord::Validations

When you want to go a little deeper and figure out exactly where the method was defined, use source_location:

1
2
irb(main):004:0> Task.new.method(:valid?).source_location
=> ["/usr/local/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0.beta2/lib/active_record/validations.rb", 55]

source_location returns an array. The first element is the path to the file where the method was defined, and the second element is the line number. With those, you know exactly where to look next.

Reading the source (without having to dig)

Once you can figure out where a method was defined, you might want to see how it’s defined.

Method can’t do that by itself. But if you install the method_source gem, you can see the source code for many methods right from your console:

1
2
3
4
5
6
7
irb(main):002:0> puts Task.new.method(:valid?).source
    def valid?(context = nil)
      context ||= (new_record? ? :create : :update)
      output = super(context)
      errors.empty? && output
    end
=> nil

You can even see the comments:

1
2
3
4
5
6
7
8
9
10
11
12
irb(main):003:0> puts Task.new.method(:valid?).comment
# Runs all the validations within the specified context. Returns +true+ if
# no errors are found, +false+ otherwise.
#
# Aliased as validate.
#
# If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
# <tt>new_record?</tt> is +true+, and to <tt>:update</tt> if it is not.
#
# Validations with no <tt>:on</tt> option will run no matter the context. Validations with
# some <tt>:on</tt> option will only run in the specified context.
=> nil

Pretty awesome, right? Your documentation is right in the console!

Introspection is awesome

Some of my favorite Ruby classes are those that let you inspect your code from within your code. Classes like Class, Module, and Method. With these, you can learn a ton about your code as it runs, and modify it on the fly. Learn these classes well, study their API, and you’ll be able to do amazing things with Ruby.

When you generate a scaffold in Rails, you’ll see the usual respond_to blocks:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
7
  def destroy
    @task.destroy
    respond_to do |format|
      format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

But some of your actions, like index, don’t have them!

app/controllers/tasks_controller.rb
1
2
3
4
5
  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
  end

This is bad. Why? If you hit /tasks.txt, and txt isn’t supported by your app, you’ll get the wrong error:

1
ActionView::MissingTemplate (Missing template tasks/index, application/index with {:locale=>[:en], :formats=>[:text], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}

This isn’t quite right. You should be telling the client that they’re requesting a format you don’t support, not that you can’t find the right file.

If this was a UnknownFormat error, you could return a better response code. Instead, these errors will get mixed together with other, unrelated errors, and it’ll be really hard to handle them.

You could add a respond_to block to your index action:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
7
8
9
  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
    respond_to do |format|
      format.html
      format.json
    end
  end

Then, you’d get the exception and error code you’d expect:

1
2
3
4
5
6
Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:05:12 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 21ms

ActionController::UnknownFormat (ActionController::UnknownFormat):
  app/controllers/tasks_controller.rb:8:in `index'

Much better. But littering all your controllers with respond_to is crazy. It feels un-Rails-ish. It violates DRY. And it distracts you from the work your controller is actually doing.

You still want to handle bad formats correctly. So what do you do?

A respond_to shortcut

If you’re not doing anything special to render your objects, you can take a shortcut. If you write:

app/controllers/tasks_controller.rb
1
2
3
4
def index
  @tasks = Task.all
  respond_to :html, :json
end

it works the same way as writing the full respond_to block in index. It’s a short way to tell Rails about all the formats your action knows about. And if different actions support different formats, this is a good way to handle those differences without much code.

Handle formats at the controller level

Usually, though, each action in your controller will work with the same formats. If index responds to json, so will new, and create, and everything else. So it’d be nice if you could have a respond_to that would affect the entire controller:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
7
8
9
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  respond_to :html, :json

  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
  end

And this actually works:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:17:37 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 7ms

ActionController::UnknownFormat (ActionController::UnknownFormat):
  app/controllers/tasks_controller.rb:8:in `index'

Exactly the kind of error we were hoping to get! And you didn’t have to mess with each action to do it.

Sometimes you’ll want to do different things depending on the state of a model. For instance, for create, you’d either redirect or re-render the form, depending on whether or not the model is valid.

Rails can handle this. But you still have to tell it which object you want it to check, with respond_with. So instead of:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
  def create
    @task = Task.new(task_params)

    respond_to do |format|
      if @task.save
        format.html { redirect_to @task, notice: 'Task was successfully created.' }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :new }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

you can write:

app/controllers/tasks_controller.rb
1
2
3
4
5
  def create
    @task = Task.new(task_params)
    flash[:notice] = "Task was successfully created." if @task.save
    respond_with(@task)
  end

This way, you separate your code from the formats you respond to. You can tell Rails once which formats you want to handle. You don’t have to repeat them in every action.

The responders gem

In Rails 4.2, there’s a catch: respond_with is no longer included. But you can get it back if you install the responders gem. And the responders gem brings some other nice features with it.

You can set flash messages in respond_with by including responders :flash at the top of your controller:

app/controllers/tasks_controller.rb
1
2
class TasksController < ApplicationController
  responders :flash

Conveniently, you can set defaults for these flash messages in your locale files.

Also, if you have the responders gem in your Gemfile and you generate a Rails scaffold, the generator will create controllers using respond_with instead of respond_to:

app/controllers/tasks_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  respond_to :html, :json

  def index
    @tasks = Task.all
    respond_with(@tasks)
  end

  def show
    respond_with(@task)
  end

  # ...

This is a lot cleaner than the scaffolds Rails comes with.

respond_with or respond_to?

If you want to return different information for different formats, you have a few options. The controller-level respond_to combined with respond_with is a great way to get short controllers. But it tends to help the most when all of your controller actions respond to the same format, and act in the way Rails expects them to.

Sometimes, though, you want to be able to have a few actions that act differently. The one-liner respond_to is great for handling that situation.

If you need more control, use the full respond_to with a block, and you can handle each format however you want.

With any of these, requests for formats you don’t support will get the right error. And both your app and its clients will be a lot less confused.

You’re working with a brand new library or feature, and you just can’t understand the documentation. Maybe it’s hard to get set up, so you have to bounce between RDocs until you learn how everything fits together. Maybe the documentation doesn’t even exist. Or maybe you just learn best by seeing lots of examples.

You need some help. But where do you learn how to use a feature, if not its documentation?

One of my favorite GitHub features

When you want to go beyond the documentation and see real-world uses of a library or feature, use GitHub’s code search.

For example, say I just read the Rails guide on Conditional GET Support. I feel like I understand it, but I want to see some more examples before I use it for real.

I could hop onto GitHub search, and look for "if stale?". Then, in the sidebar, pick code and Ruby:

And now I have tons of great examples of how stale? could be used.

Not all of the examples are interesting. But in one listing, I notice the author using Post.maximum:

app/controllers/archives_controller.rb
1
2
3
4
5
6
7
class ArchivesController < ApplicationController
  def index
    if stale?(last_modified: (Post.maximum(:updated_at) || EPOCH).utc, public: true)
      @months = Post.find_all_grouped_by_month
    end
  end
end

That seems like a great way to use stale?. And if I hadn’t seen this example, I might not have thought to try it.

How should you use what you find?

When you search open-source code, you get hundreds of examples for nearly any feature. You’ll notice where the documentation makes sense, and where it’s over-simplified. And you’ll see objects working together in real code. That will teach you more about how classes are connected than any RDoc can.

Still, use the examples to learn new things, not to cargo cult into your own project. Using code without understanding it is the fastest way to a poorly designed system.

In my example, maximum might not be the right thing to do in my project. I shouldn’t copy the line without learning more about it. Without understanding when it makes sense to use. But examples can teach you things you didn’t know before. And they’re a great way to decide what to learn about next.

Like any search, it’ll take some practice to get good results. But I’ve learned a lot from the code I’ve found, and I know you will too.

When I was first learning the board game Go, I bought and read a few introductory books. They taught me the rules, and some basic strategy. I knew that there was a fun game there. But I just wasn’t seeing it.

When it came time to play my own games, I was confused and stressed out. There were 361 possible moves I could make, but which of those was the best one? Not even that, which of those were even acceptable? Using the information I got from the first books, I could maybe narrow decent moves down to about a hundred, but I still had trouble knowing where to start, and what to do. And it just wasn’t fun to me.

I felt like I couldn’t even play the game unless I studied everything first.

So, on a friend’s recommendation, I picked up another book. The book was called “The Second Book of Go.” It had short chapters, each on a specific topic that beginners tend to struggle with. And it gave me some processes I could follow, so I could know that I wasn’t making insane moves.

It taught me the reason behind crazy-looking strategies, and it taught me tricks to make better decisions and evaluate my own moves. And it showed me that even wrong moves had value.

When I started playing again, I began to have fun.

As long as I’ve written here, I’ve heard from people learning Rails that were in the same boat as I was learning Go. They heard it was supposed to be fun, but it was actually just frustrating. They didn’t know where to start. The things they learned didn’t stick with them. They couldn’t spend time learning consistently enough to grow as a Rails developer. Most of all, they were overwhelmed, because the space of possibilities in front of them seemed too big.

If this sounds familiar, I wrote a book for you. It’s meant to bring the joy of Ruby and Rails to those who were about to give up. To show that with a little structure, a little practice, and a little curiosity, you can write your own Rails applications, and have fun doing it.

It’s available for pre-sale, starting today. It’s 25% off until it’s finished. And when you buy it, you’ll get today’s draft immediately, and updates to it from here on out.

I hope you enjoy it.

(This is a short excerpt from Practicing Rails. Sign up here to get the first chapter free!)

So, you’re working on a new app, and Rails just generated a test for you:

test/models/bug_test.rb
1
2
3
4
5
6
7
require 'test_helper'

class BugTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
end

You uncomment it, come up with a name, and you’re ready to write your test, right? But then what? What do you write first? What should your test code look like?

If you follow a simple pattern, you’ll turn those stubbed out lines of code into clear, well-structured test cases.

The three-phase test pattern

Your test cases should work in three phases:

  1. First, you set some stuff up (“Arrange”)
  2. Then, you do something (“Act”)
  3. Then, you make sure that what you expected to happen, actually happened. (“Assert”)

For instance, imagine you were testing a method on an array in Ruby. Following this pattern, your test could look like:

1
2
3
4
5
6
7
8
9
10
test "Array#sort will sort an array of numbers" do
  # arrange
  unsorted_array = [7, 4, 2, 3]

  # act
  sorted_array = unsorted_array.sort

  # assert
  assert_equal [2, 3, 4, 7], sorted_array
end

Simple enough. But every part of the test has a place to go, and each stage of the test almost tells you how to write it.

Sometimes, you won’t need an Arrange phase, or the Act and Assert phases will be combined. But it still helps to think about all three phases as you write your tests.

The Assert phase gotcha

There’s a trick to the Assert phase: you shouldn’t use the same logic that the Act phase used in the Assert phase. You should always take two paths to the same answer. Otherwise, you won’t notice bugs in the code you’re calling, because it’s just getting called again in the Assert phase.

For example, if you’re doing some math:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
test "average returns the average of a set of numbers" do
  # arrange
  numbers = [1, 2, 3, 4]

  # act
  average = numbers.average

  # assert

  # this is bad
  assert_equal [1, 2, 3, 4].average, average

  # this is better
  assert_equal 2.5, average
end

Calling [1, 2, 3, 4].average again in the Assert phase is bad, because average could return almost anything and that assertion would still pass.

Here, that’s pretty clear. But even when things get more complicated, make sure you’re not just running the same code twice. Otherwise you’re only verifying that your method was called, not that it worked the way you expect it to.

Usually, the easiest way to take a second path to the answer is to find the answer by hand and hardcode it. It can be brittle, but it’s better than your tests breaking without you realizing it.

Why three phases?

If you split your tests into those three phases, you have simpler questions to answer. Instead of “How should I write this test?”, you can focus on each phase: “How should I set this test up?”, “What am I testing?”, “What should the answer look like?”

These questions still might not have easy answers, but the answers will be a lot easier than thinking about the entire test at once. And if you’re lucky, you can even share phases between related tests, making your next test much less painful to write.

A few weeks ago, I wrote about how RubyGems manages Ruby’s load path. But Rails doesn’t use RubyGems directly — it uses Bundler to manage its gems.

If you don’t know how Bundler works, the way gems get pulled into Rails might seem a little too magical. How does adding a line to a Gemfile get code into your app? How do Bundler, Rails, and RubyGems work together to make handling dependencies easy?

Why Bundler?

I think of Bundler as a strict gem manager. That is, Bundler helps you install the right versions of the gems you need, and forces your app to only use those versions.

This turns out to be really helpful. To understand why, you have to go back to the world before Bundler.

Before Bundler, it was still pretty easy to install the right versions of your gems with some kind of setup script:

bin/setup
1
2
3
gem install rails -v 4.1.0
gem install rake -v 10.3.2
...

(That is, as long as Rails 4.1’s dependencies don’t conflict with Rake 10.3.2’s dependencies!)

But what happens when you’re working on a few different Rails apps, each depending on different versions of gems? Unless you’re really careful, you’ll run into the terrible gem activation error:

gem_error
1
2
Gem::Exception: can't activate hpricot (= 0.6.161, runtime),
already activated hpricot-0.8.3

Ugh. That message still gives me nightmares. It usually meant you’re in for a day of installing and uninstalling gems, so you can get just the right versions on that machine. And all it takes is an accidental gem install rake to completely mess up all of your careful planning.

rvm gemsets helped with this problem for a while. But they needed some time to set up, and if you accidentally installed into the wrong gemset, you’d be back to the same problem. With Bundler, you rarely have to think about your dependencies. Your apps usually just work. And Bundler takes a lot less setup than gemsets did.

So, Bundler does two important things for you. It installs all the gems you need, and it locks RubyGems down, so those gems are the only ones you can require inside that Rails app.

How does Rails use Bundler?

At its core, Bundler installs and isolates your gems. But that’s not all it does. How does the code from the gems in your Gemfile make it into your Rails app?

If you look at bin/rails:

bin/rails
1
2
3
4
5
6
7
8
#!/usr/bin/env ruby
begin
  load File.expand_path("../spring", __FILE__)
rescue LoadError
end
APP_PATH = File.expand_path('../../config/application',  __FILE__)
require_relative '../config/boot'
require 'rails/commands'

You’ll see that it loads Rails by requiring ../config/boot. Let’s look at that file:

config/boot
1
2
3
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

require 'bundler/setup' # Set up gems listed in the Gemfile.

Hey, it’s Bundler! (Also, I just learned you can choose a different Gemfile to use by setting the environment variable BUNDLE_GEMFILE. That’s pretty cool.)

bundler/setup does a few things:

  • It removes all paths to gems from the $LOAD_PATH (which reverses any load path work that RubyGems did).
  • Then, it adds the load paths of just the gems in your Gemfile.lock back to the $LOAD_PATH.

Now, the only gems you can require files from are the ones in your Gemfile.

So all the gems you need are on your load path. But when you use RubyGems by itself, you still have to require the files you need. Why don’t you have to require your gems when you use Rails with Bundler?

Take a quick look at config/application.rb, which runs after Rails boots:

config/application.rb
1
2
3
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

It’s Bundler again! Bundler.require requires all the gems in all the groups you pass to it. (By “groups”, I mean the groups you specify in your Gemfile.)

Which groups are in Rails.groups, though?

railties/lib/rails.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   # Returns all rails groups for loading based on:
    #
    # * The Rails environment;
    # * The environment variable RAILS_GROUPS;
    # * The optional envs given as argument and the hash with group dependencies;
    #
    #   groups assets: [:development, :test]
    #
    #   # Returns
    #   # => [:default, :development, :assets] for Rails.env == "development"
    #   # => [:default, :production]           for Rails.env == "production"
    def groups(*groups)
      hash = groups.extract_options!
      env = Rails.env
      groups.unshift(:default, env)
      groups.concat ENV["RAILS_GROUPS"].to_s.split(",")
      groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) }
      groups.compact!
      groups.uniq!
      groups
    end

Well, that explains that. Rails.groups is going to be [:default, :development] when you’re running Rails in development mode, [:default, :production] in production mode, and so on.

So, Bundler will look in your Gemfile for gems belonging to each of those groups, and call require on each of the gems it finds. If you have a gem nokogiri, it’ll call require "nokogiri" for you. And that’s why your gems usually just work in Rails, without any extra code on your part.

Know your tools

If you understand the tools you use well, it’ll be easier to work with them. So if you find yourself using something all the time, it’s worth taking a few minutes to dig into it a little more.

If you’re working in Ruby and Rails, you’ll use gems every day. Take the time to learn them well!

There are lots of good places to learn Ruby. But learning isn’t just reading books or watching videos. It’s running head-first into a problem, getting stuck, struggling, getting frustrated, looking things up, having it click, playing around with it, and finally (finally!) getting something working.

You have to use the things you learn, or they won’t stick with you. And there are a few great ways I’ve found to do just that.

Ruby Quiz

Ruby Quiz is a group of over 150 short, interesting problems to solve with Ruby. Things from converting Roman Numerals to generating ASCII-art dungeons. Each problem has solutions, too — you can see different approaches to the same question. Ruby Quiz has been around forever, and it’s still a lot of fun.

exercism.io

exercism.io starts like Ruby Quiz — you’ll build solutions to small programming problems. But in exercism, after you submit your solution, you share it with other people. You’ll review your code, and refactor it to make it even better.

Your goal with exercism isn’t just working code. It’s refactoring toward small, simple code. You’ll practice your refactoring and object-oriented design skills. And those will stick with you through your entire programming career.

Try it in a tiny app

Programming challenges are great for building your general Ruby knowledge. But sometimes you’ll want to try a feature you just learned about, so you can understand it better.

So, try it in an app. Generate a new Rails app with a scaffold or two. Dedicate it to playing with the feature you want to learn. Even if you’re not doing something Rails-specific, Rails’ code generators are great for trying new things without much setup. You don’t have to worry about setting up tests, requiring the right files, getting Rake set up, or anything like that.

This is how I’ve been playing with the new Rails 4.2 features, and it’s the way I try most of the things I’ve written about here. (It’s also the topic of the first chapter of my book).

What have you forgotten?

I have a long, long list of things I’ve forgotten because I never used them. And that’s just not a good use of my time.

So, balance your reading and viewing with some practice and play. Do some challenges, or build some tiny apps. You’ll be surprised how much more quickly you’ll pick stuff up.

Most of the time, gems in Ruby Just Work. But there’s a big problem with Ruby magic: when things go wrong, it’s hard to find out why.

You won’t often run into problems with your gems. But when you do, Google is surprisingly unhelpful. The error messages are generic, so they could have one of many different causes. And if you don’t understand how gems actually work with Ruby, you’re going to have a tough time debugging these problems on your own.

Gems might seem magical. But with a little investigation, they’re pretty easy to understand.

What does gem install do?

A Ruby gem is just some code zipped up with a little extra data. You can see the code inside a gem with gem unpack:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
~/Source/playground jweiss$ gem unpack resque_unit
Fetching: resque_unit-0.4.8.gem (100%)
Unpacked gem: '/Users/jweiss/Source/playground/resque_unit-0.4.8'
~/Source/playground jweiss$ cd resque_unit-0.4.8
~/Source/playground/resque_unit-0.4.8 jweiss$ find .
.
./lib
./lib/resque_unit
./lib/resque_unit/assertions.rb
./lib/resque_unit/errors.rb
./lib/resque_unit/helpers.rb
./lib/resque_unit/plugin.rb
./lib/resque_unit/resque.rb
./lib/resque_unit/scheduler.rb
./lib/resque_unit/scheduler_assertions.rb
./lib/resque_unit.rb
./lib/resque_unit_scheduler.rb
./README.md
./test
./test/resque_test.rb
./test/resque_unit_scheduler_test.rb
./test/resque_unit_test.rb
./test/sample_jobs.rb
./test/test_helper.rb
~/Source/playground/resque_unit-0.4.8 jweiss$

gem install, in its simplest form, does something kind of like this. It grabs the gem and puts its files into a special directory on your system. You can see where gem install will install your gems if you run gem environment (look for the INSTALLATION DIRECTORY: line):

1
2
3
4
5
6
~ jweiss$ gem environment
RubyGems Environment:
  - RUBYGEMS VERSION: 2.2.2
  - RUBY VERSION: 2.1.2 (2014-05-08 patchlevel 95) [x86_64-darwin14.0]
  - INSTALLATION DIRECTORY: /usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0
  ...
1
2
3
~ jweiss$ ls /usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0
bin           bundler     doc         gems
build_info    cache       extensions  specifications

All of your installed gem code will be there, under the gems directory.

These paths vary from system to system, and they also depend on how you installed Ruby (rvm is different from Homebrew, which is different from rbenv, and so on). So gem environment will be helpful when you want to know where your gems’ code lives.

How does gem code get required?

To help you use the code inside of your gems, RubyGems overrides Ruby’s require method. (It does this in core_ext/kernel_require.rb). The comment is pretty clear:

core_ext/kernel_require.rb
1
2
3
4
5
6
7
8
9
10
11
  ##
  # When RubyGems is required, Kernel#require is replaced with our own which
  # is capable of loading gems on demand.
  #
  # When you call <tt>require 'x'</tt>, this is what happens:
  # * If the file can be loaded from the existing Ruby loadpath, it
  #   is.
  # * Otherwise, installed gems are searched for a file that matches.
  #   If it's found in gem 'y', that gem is activated (added to the
  #   loadpath).
  #

For example, say you wanted to load active_support. RubyGems will try to require it using Ruby’s require method. That gives you this error:

core_ext/kernel_require.rb
1
2
3
4
LoadError: cannot load such file -- active_support
  from (irb):17:in `require'
 from (irb):17
 from /usr/local/bin/irb:11:in `<main>'

RubyGems looks at that error message, and sees that it needs to find active_support.rb inside of a gem, instead. To do that, it’ll scan through its gems’ metadata, looking for a gem that contains active_support.rb:

1
2
irb(main):001:0> spec = Gem::Specification.find_by_path('active_support')
=> #<Gem::Specification:0x3fe366874324 activesupport-4.2.0.beta1>

Then, it activates the gem, which adds the code inside the gem to Ruby’s load path (the directories you can require files from):

1
2
3
4
5
6
irb(main):002:0> $LOAD_PATH
=> ["/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0/x86_64-darwin14.0"]
irb(main):003:0> spec.activate
=> true
irb(main):004:0> $LOAD_PATH
=> ["/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/i18n-0.7.0.beta1/lib", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/thread_safe-0.3.4/lib", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta1/lib", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/site_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/vendor_ruby", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0", "/usr/local/Cellar/ruby/2.1.2/lib/ruby/2.1.0/x86_64-darwin14.0"]

Now that active_support is on the load path, you can require the files in the gem just like any other piece of Ruby code. You can even use the original version of require, the one that was overwritten by RubyGems:

1
2
irb(main):005:0> gem_original_require 'active_support'
=> true

Cool!

A little knowledge goes a long way

RubyGems might seem complicated. But at its most basic level, it’s just managing Ruby’s load path for you. That’s not to say it’s all easy. I didn’t cover how RubyGems manages version conflicts between gems, gem binaries (like rails and rake), C extensions, and lots of other stuff.

But knowing RubyGems even at this surface level will help out a lot. With a little code reading and playing in irb, you’ll be able to dive into the source of your gems. You can understand where your gems live, so you can make sure that RubyGems knows about them. And once you know how gems are loaded, you can dig into some crazy-looking loading problems.