Max Krebs

Ruby Bare Names

I’ve been slowly making my way through The Ruby Programming Language book and I came across something interesting.

With Ruby variables, you can scope variable names by adding a prefix symbol to the beginning of the name. For example:

type = 'Local Variable'
TYPE = 'Constant'
$type = 'Global Variable'
@type = 'Instance Variable'
@@type = 'Class Variable'

In Ruby1, local variables that don’t have a prefix symbol (i.e. local variables) have a bit of peculiar behavior that leads to some interesting patterns. If the Ruby interpreter comes across a variable name, it checks for 1) a value assigned to that variable name, and if that fails it checks for 2) a method with that name.

def ambiguous_number
  2
end

ambiguous_number = 1
puts ambiguous_number

If you copy and paste that bit of code into a Ruby file and execute it, the output will be 1. However, this piece of code is different.

def ambiguous_number
  2
end

puts ambiguous_number

In most other programming languages (I think), you will get some variation of a NameError to tell you that ambiguous_number isn’t defined. In Ruby, the program will output 2.

This is, superficially, a nifty quirk of the language, but when you get into some deeper coding, there are some interesting patterns that use this quirk.

The first place I noticed this pattern was in Rails strong parameters. Before strong parameters were introduced in Rails 4, you could write your controller like this:

class UsersController < ActionController::Base
  def create
    @user = User.new(params[:user])
    ....
  end
end

That create method creates a new user from the :user parameters hash passed to the controller from the form in the view.

The strong parameters way of writing this controller is:

class UsersController < ActionController::Base

  def create
    @user = User.new(user_params)
    ....
  end

  private

  def user_params
    params.require(:user).permit(:name)
  end
end

If you look at this, you would think the create action is making a new User from the values in the local variable user_params, but you would be wrong. Look closely, and you will notice the private method below called user_params. The Ruby interpreter sees the call to user_params and first looks for a local variable with that name, but when it doesn’t find one, it uses the return value of the method user_params. Handy.

I’ve heard this feature of Ruby described as “Bare Names.” The real value of bare names, that I’ve found so far, is within the context of the Extract Method refactoring pattern.

In short, extracting a method would entail taking functionality out of a method and creating a new method that contains that functionality in order to reduce the amount of responsibility of any one method. An easy way to do this is to use bare names to extract fairly complicated logic using local variables into their own methods.

This example is taken from a Rails app I’ve been building as just a learning/example app from an intermediate Rails series of screencasts. Its basically just a twitter clone. The controller below is for a FollowingRelationship model, which controls the follower/followee relationship between users.

class FollowingRelationshipsController < ApplicationController
  def create
    user = User.find(params[:user_id])
    current_user.followed_users << user
    redirect_to user
  end
end

Not the most complex controller, but its ripe for refactor.

class FollowingRelationshipsController < ApplicationController
  def create
    current_user.follow user
    redirect_to user, notice: "Now following user."
  end

  private

  def user
    @_user ||= User.find(params[:user_id])
  end
end

We extracted out the core functionality of one line, mainly setting a local variable from the parameters and put that in a method called user. This refactor uses the bare names functionality of Ruby, to extract a method out of a (albeit simple) overly complicated controller action.2

This was a delightful discovery. I’ve seen the bare words pattern used before (especially in the context of strong params) but it was exciting to find a concrete explanation for the behavior.


  1. I think this is a Ruby unique feature, I can’t think of any other language that handles variable invocation and assignment this way, but I am probably wrong. [return]
  2. The @_user syntax there is just a convention to signal that you should be using the method user and not the variable @user [return]