Do your co-workers snicker at your sentence-length shell aliases? I’m here to tell you it’s okay because my aliases border on the Dostoyevskian, too.
Some commands you do a thousand times a day. They deserve super-short aliases:
alias be="bundle exec"
alias s="bundle exec rspec"
alias cuc="bundle exec cucumber"
Like h() or t() in Rails, the more often you invoke a command, the more acceptable it becomes to have a short, cryptic alias.
However, there’s a class of commands I find myself running about 1-20 times a day: interacting with our staging and production environments on Heroku:
# Heroku staging
alias staging='heroku run console --remote staging'
alias staging-process='watch heroku ps --remote staging'
alias staging-releases='heroku releases --remote staging'
alias staging-tail='heroku logs --tail --remote staging'
# Heroku production
alias production='heroku run console --remote production'
alias production-process='watch bundle exec heroku ps --remote production'
alias production-releases='heroku releases --remote production'
alias production-tail='heroku logs --tail --remote production'
# Heroku databases
alias db-pull-staging='heroku db:pull --remote staging --confirm `basename $PWD`-staging'
alias db-pull-production='heroku db:pull --remote production --confirm `basename $PWD`-production'
alias db-copy-production-to-staging='heroku pgbackups:restore DATABASE `heroku pgbackups:url --remote production` --remote staging --confirm `basename $PWD`-staging'
alias db-backup-production='heroku pgbackups:capture --remote production'
alias db-backups='heroku pgbackups --remote production'
Here’s where Neckbeard next to you silently pities your Fisher-Price programming style. What self-respecting programmer would type all that?!
Well, through the magic of autocompletion, you never type more than a few characters for each command. They might look goofy, but they’re memorable.
If you’d like these aliases and other goodies, they’re packaged up in our dotfiles.
Then, the next time you feel your pair programming partner smirking over your shoulder, just tell ‘em: “I learned to alias shell commands with Hooked on Phonics!”
Aside from a handful of internal code clean up, Factory Girl 2.2 brings a handful of awesomeness to the table. Factory Girl 2.1 was released a mere month and a half ago but loads of improvements have been added since then. Some key features:
When we introduced traits, there were a couple of caveats: you couldn’t
override traits’ attributes from child factories, and you couldn’t overwrite
traits’ attributes when using FactoryGirl.modify. Not the case anymore!
We’ve been hammering away at Factory Girl’s internals, cleaning things up and
delaying factory resolution as late as possible. This allows for:
FactoryGirl.define do
factory :user do
name "Stranger"
trait :male do
name "Jon Snow"
gender "Male"
end
factory :male_user do
male
end
factory :brandon do
male
name "Brandon"
end
end
end
FactoryGirl.modify do
factory :brandon do
name "Brandon Stark"
end
end
This may sound a bit odd. Why would you ever want to define a parent factory after a child factory? When you’ve split your factories up across different files and don’t want to prefix file names in order for the files to be loaded in a specific order.
Factory Girl looks in six places by default: factories/, factories.rb, spec/factories/, spec/factories.rb, test/factories/, and test/factories.rb. If you’ve split up your factories within one of the directories, that’s wonderful; however, what if you want a “base” factory file and multiple factory files for the various children? Before 2.2, you’d have to name that base file in order to force it to be loaded before children, and that’s just gross.
Transient attributes are a relatively new feature allowing attributes to be
passed via a hash when creating/building that don’t actually interact with the
instance (or hash, when using attributes_for). The old syntax required
calling #ignore on individual attribute declarations, which didn’t really
look great. Now, you define all your ignored attributes in a block.
FactoryGirl.define do
factory :user do
ignore do
rockstar true
four { 2 + 2 }
end
name { "John Doe#{" - Rockstar" if rockstar}" }
end
end
The old ignore syntax has been deprecated and will be removed in 3.0.
Have you ever done this?
let(:old_published_post) do
create(:post, created_at: 2.years.ago).tap do |post|
post.publish!
end
end
Now, you can just pass a block to the syntax methods (create, build,
build_stubbed, and attributes_for) and they’ll yield themselves; no more
tap! It’s a simple enough change, but four characters fewer is four
characters fewer.
Aside from getting in solid pull requests, we’re going to be reworking the test suite so it’s much more flexible and continue reworking the inner workings of the gem. There’s currently a handful of code surrounding how to evaluate attributes and the order in which we should do so that we’d like to remove completely and have attributes resolve lazily.
We’re also considering a new syntax method, decorate, which would allow for:
FactoryGirl.define do
factory :post do
title "My great post!"
body "An awesome story"
decorate :old do
title "How is this even around still?"
created_at { 2.years.ago }
end
decorate :archived do
title "This shouldn't be on the homepage"
archived true
decorate :unpublished do
published false
end
end
end
end
This would give us four factories: post, old_post, archived_post, and
archived_unpublished_post.
What features would you like to see in Factory Girl? Post them on the GitHub issues page and let us know in the comments!
Every developer runs into the dreaded nil object error: NoMethodError in Ruby, AttributeError in Python, and NullPointerException in Java. These errors are one of the largest sources of bugs. Even most static languages allow nil objects to silently pass as any type of object, and it’s just as easy in Ruby to let a nil object slip into seemingly well-factored code. If this is such a widespread and well-understood problem, why aren’t there best practices and solutions to solve it? There are actually many patterns and solutions for avoiding nil object errors, but you don’t see them too often in the Ruby community.
The most direct and bullet-proof way to avoid nil object errors is to avoid nil objects. Sometimes nil is passed around simply as a convenient “other” value or placeholder, and this is an abuse of the concept of nil. Finding and eliminating these abuses isn’t too hard, a program often needs to handle the concept of “nothing” in some way. Although nil is the most basic way to handle this case, it’s often not the best.
As an example, let’s say you’re writing a software as a service application. SaaS applications frequently need to track which users are members of which projects. Some areas require administrator permissions, and you’d probably end up with code similar to this:
class User < ActiveRecord::Base
has_many :memberships
def admin_of?(project)
membership_for(project).admin?
end
def membership_for(project)
memberships.where(:project_id => project).first
end
end
You can probably spot the issue with this snippet. If the user isn’t a member at all, membership_for will return nil and you’ll get a NoMethodError. We can easily change admin_of? to check for a missing membership, but that’s not really the problem with this code.
The problem with nil is that it’s hard to know when to expect it. As a developer coming onto this project, or as a developer coming back to a piece of code after a while, it’s hard to know which methods might return nil. A method named membership_for sounds like it should return a Membership, not nil. Unless you dive through every method you call (and every method those methods call, and so on), you can’t tell if a nil might be returned somewhere down the line. Rather than adding the nil check in this one place and continuing to program in paranoid fear, let’s look at some possible solutions besides returning nil instead of a Membership.
One alternative to returning nil is to raise an exception in the “nothing” case. The implicit contract of the membership method is that it will return a Membership object, so it makes sense to throw an exception in the cases that we can’t:
class User < ActiveRecord::Base
class NoMembership < StandardError; end
def membership_for(project)
memberships.where(:project_id => project).first or
raise NoMembership
end
end
In this case, we don’t expect that you’ll ever call membership_for (or admin_of?) for a user that isn’t a member, so we can simply throw an exception in the unexpected case. The exception allows us to specifically handle the unexpected case of a missing membership (whereas NoMethodError is too generic to rescue), and it’s much easier to debug if it should happen in production.
Exceptions are useful when a method might not have a value to return, but nothing useful can be done unless a return value exists.
However, in a real SaaS, we’ll need to ask about permissions for users that aren’t members of projects, so raising an exception isn’t acceptable.
Another option that I rarely see in Ruby code is the special nil object. A nil object can be written to handle situations that a method needs to handle “nothing” without returning an object that violates the implicit contract of the method:
class User < ActiveRecord::Base
def membership_for(project)
memberships.where(:project_id => project).first or
NilMembership.new
end
end
class NilMembership
def admin?
false
end
end
With the NilMembership instance, the admin_of? method doesn’t need to worry about the return value. It will usefully respond to admin? whether or not the admin is a member.
Nil objects are useful when a method may need to return nothing and the returning method clearly knows how to handle the “nothing” edge case.
Unfortunately, this still won’t work for our real SaaS use case, because we’ll need to handle situations where a user is a member but isn’t an admin.
Going back to our original code, now with an added member_of? method:
class User < ActiveRecord::Base
has_many :memberships
def admin_of?(project)
membership_for(project).admin?
end
def member_of?(project)
membership_for(project).present?
end
def membership_for(project)
memberships.where(:project_id => project).first
end
end
The member_of? method works fine, but admin_of? is back to raising NoMethodError for missing memberships. We still don’t want to just check for nil in that one client method, so let’s look at another option: the maybe pattern.
This pattern is a little more heavy-handed and requires some setup. Here’s a simple implementation:
class Object
def maybe
Some.new(self)
end
end
class NilClass
def maybe
None.new
end
end
class Some
def initialize(object)
@object = object
end
def get
@object
end
def present?
true
end
def blank?
false
end
end
class None
class Unwrapped < StandardError; end
def get
raise Unwrapped
end
def present?
false
end
def blank?
true
end
end
And here’s how we’d use it in our application:
class User < ActiveRecord::Base
has_many :memberships
def admin_of?(project)
membership = membership_for(project)
if membership.present?
membership.get.admin?
else
false
end
end
def member_of?(project)
membership_for(project).present?
end
def membership_for(project)
memberships.where(:project_id => project).first.maybe
end
end
The idea behind the maybe pattern is to force client methods to unwrap the return value before using it. It’s impossible to be unaware that membership_for might return nothing, because it never returns an object that acts like a Membership. You could argue that this is a violation of the implicit contract based on the method’s name, but the return value at least prevents a developer from missing possible edge cases.
The maybe pattern is useful for situations that you need to return nothing but there’s no obvious edge case. In those situations, it makes sense to force consumer methods to check for nothing and handle edge cases on their own.
Which pattern you choose (and there are other patterns out there) depends on your situation, but it’s likely you shouldn’t choose to return nil. Nil is a sad shell of an object, and it’s just not polite to hand a developer a nil when he or she asked for a Membership. Try helping your fellow developers out and find something else to return.
We often augment an existing Rails team or help build a Rails team on behalf of our clients. In the process, we do feature branch code reviews. Among other reasons, we do them to get everyone comfortable with Ruby and Rails idioms.
The following is a list of real code we’ve refactored (variable names changed to protect the innocent). This is mostly beginner-level stuff so please hold off on value judgments if you’re experienced.
Original:
render :partial => 'admin/shared/errors',
:locals => { :errors => @user.errors }
Refactored:
render 'admin/shared/errors', :errors => @user.errors
The documentation for render says:
If no options hash is passed or :update specified, the default is to render a partial and use the second parameter as the locals hash.
Original:
existing_song = Song.where(:user_id => user_id,
:album_id => album_id).first
if existing_song
Refactored:
if Song.exists?(:user_id => user_id, :album_id => album_id)
The documentation for exists? says:
Returns true if a record exists in the table that matches the id or conditions given, or false otherwise.
Original:
<%= event.end_date.nil? ? '' : event.end_date.to_s(:long) %>
Refactored:
<%= event.end_date.try(:to_s, :long) %>
The documentation for try says:
Invokes the method identified by the symbol method, passing it any arguments and/or the block specified, just like Ruby Object#send. Unlike that method, nil will be returned if the receiving object is a nil object or NilClass.
It’s usually worth spending time identifying why you have to do this at all. If you can remove the scenario where the object is nil, that’s preferable.
Original:
if !town
town = user.town
end
Refactored:
town ||= user.town
Read it something like:
town or assign town
Original, in a migration file:
group_ids.each_with_index do |id, position|
group = Group.find(id)
if group
group.position = position
group.save!
end
end
Refactored:
group_ids.each_with_index do |id, position|
update "update groups set position = #{position} where id = #{id}"
end
By using ActiveRecord methods, particularly #save!, the original version increases the risk that the migration won’t run in the future.
If a validation is added later that causes the data for a future developer or CI box or performance/staging environment to fail validation, the migration will raise an error when all we wanted to do was set some initial positions.
The solution is to use straight SQL. Use the documentation on ActiveRecord::ConnectionAdapters::DatabaseStatements as your guide.