Retrieving Values from Hashes

In Ruby, there are at least two ways to get a specific value from a hash with two different results if the key is not found.

1. Hash#fetch

h = { "a" => 100, "b" => 200 }
h.fetch("z")
=> KeyError: key not found: "z"from (pry):26:in `fetch'

2. hsh[key] → value

h = { "a" => 100, "b" => 200 }
h["z"]
=> nil

Which one you want to use depends on whether you want to raise an error if it doesn’t exist or just check if it is nil.

Raising ActiveRecord::Rollback

I had a bit of code that I was running in a transaction block. Like so:

ActiveRecord::Base.transaction do
  @rating = Rating.new(rater: @user, rateable: @movie, score: params[:score])
  if !@rating.save
    Rails.logger.error("Error saving rating")
    raise ActiveRecord::Rollback
  end
end

I kept trying to test this by doing:

expect { post :create etc }.to raise_error ActiveRecord::Rollback

Total failure. Couldn’t figure out why for a while. Here’s the reason: raising ActiveRecord::Rollback just triggers a rollback of the transaction and does so silently. What I should’ve done is raise a different type of error (TBD) and that will still trigger a rollback of the transaction but the error will actually be raised and we can return an appropriate page to the user.

More info on StackOverflow.

Custom Validators

As an exercise, I created a simple custom validator. I had done this before at work, but I had managed to forget how to do it between then and now. I guess that’s why I need a bit of extra practice :)

So the idea is that, instead of including this ugly regex in the model, you can pull it out (or whatever you are using to validate your attribute) and put it in a separate validator class. It makes the model much simpler and makes it so it is no longer responsible for the logic behind the validation.

If you are using Rails, you would just put PhoneValidator within the validators folder and it will find it without requiring it in the model as I do here.

# person.rb

require 'phone_validator'

class Person
  include ActiveModel::Validations

  validates :phone_number, phone: true

  attr_accessor :phone_number

  def initialize(attributes = {})
    @phone_number = attributes[:phone_number]
  end
end

# phone_validator.rb

class PhoneValidator < ActiveModel::EachValidator
  PHONE_REGEX ||= /^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/

  def validate_each(record, attribute, value)
    unless value =~ PHONE_REGEX
      record.errors[attribute] = "invalid phone number formatting" 
    end
  end
end

Converting Seconds to Midnight Back to Time

Rails has a nice little function for it’s DateTime class called ‘seconds_since_midnight’. Super handy if you (for some reason) just want to store time, without a date in your database. However, here is the next problem you will come across: how do I display this value of seconds as an actual, human-readable time?

Luckily, this is simple:

def convert_to_time_from_second_to_midnight(seconds)
  hh, mm = seconds.divmod(60)[0].divmod(60)
  Time.parse('%d:%d' % [hh, mm]).strftime("%I:%M %p")
end

divmod is an interesting little function that I’ve never used prior to writing this.  It’s very simple: just returns the quotient and the modulus. It helps us get the hours and minutes within just one line. Then all we have to do is format it and the result is a nicely formatted time like so “12:30 PM”.

Sandi Metz' Rules For Developers

I came across this post from thoughtbot about Sandi Metz’ rules for developers. This is a bit of an older post, but I had a few thoughts about it.

THE RULES:

  1. Classes can be no longer than one hundred lines of code.
  2. Methods can be no longer than five lines of code.
  3. Pass no more than four parameters into a method. Hash options are parameters.
  4. Controllers can instantiate only one object. Therefore, views can only know about one instance variable and views should only send messages to that object (@object.collaborator.value is not allowed).

How a mid-level developer feels about these rules:

  1. This tends to be pretty easy for me to keep to for regular classes, less so for specs. It’s hard to argue with this rule and it’s pretty *relatively* easy to follow.
  2. This one is a bit harder. Mainly, as thoughtbot points out, if you follow this rule, you can’t use elsif with else if following this rule. Sometimes, it’s not worth it to break things up. However, I do try to follow this rule as often as possible.
  3. This is another hard one. If you need more than four values, storing them in an object works fairly well. However, sometimes you don’t want to bulk up your code by creating another object instead of just passing params/a hash.
  4. I’m definitely a fan of the Facade Pattern as well. Keeping one instance variable per controller is another one that is fairly easy to keep.

Even for the ones that I find hard to follow, I am trying to keep to these rules with my own code. Definitely worth reviewing and incorporating into your development process.

Null Objects in Ruby

I just did an exercise running through null objects in ruby. We don’t really use them at any company I’ve worked for, so it was interesting to try out a new technique. If you are unfamiliar with null objects here’s the idea:

Null objects are beneficial when you would otherwise be checking if an object is nil or empty throughout your code.

The example in the assignment was subscriptions. You have a user and a user is attached to a subscription. However, a subscription can be a free trial or no plan, in addition to regular, paid subscription. For a free trial, price and charge are both 0 and nil, respectively. Instead of checking if subscription.nil? I can create a NullSubscription and do something like this within the user class:

def subscription
  if free_trial?
    FreeTrial.new
  else
    @subsciption || NullSubscription.new
  end
end

So now, instead of checking if @subscription is nil and then setting price, we can call @subscription.price and always get a real value (assuming we are seeing price to zero in our NullSubscription class.

Random Rubyisms That I Keep Forgetting

I haven’t been blogging because I thought that I hadn’t really solved any problems recently worth writing about. However, I forgot that I just recently came across a few Rubyisms that I had totally missed (or learned and forgotten). Here are a few bits that were enlightening to me:

  • if x && y: If x is nil, then y doesn’t run. I’ve had a few double if statements in my code previously because I forgot that the second part of the statement won’t even run if the first is nil/false.
  • x = if y then b else c end: assigned x = b if y is true, else c. I knew the inline x = b if y, but didn’t quite realize that you could do the full if else. NOTE: this is kept on one line for the sake of bullets. If you were really writing it, you would want to split it out into separate lines, with the first line being x = if y.
  • case statement when/then: Assuming you know what a full normal case statement looks like (if not, here’s a nice little post), have you seen them written as when/then? For example: when x then :is_x. To me that is much more easy to read than a when x (new line) :is_x. Definitely a personal preference though :)

That’s all for now. But I also have some Python/Ruby differences that I’ve found intriguing recently.

FactoryGirl vs. Bare Domain Objects

I’ve been doing a fair amount of research into testing and what are the best and fasted way to test. Recently, someone at work brought up the fact that using factories can drastically slow down your test suite. Especially when, like us, you create other factories within factories (ie. I need an advertiser for a campaign, so when I use Factory.build(:campaign), it also does Factory.create(:advertiser)). I tried using Factory.stub (check out this article), but it still would create in the background and I couldn’t change that without wrecking all of our other tests. I decided to start testing with bare domain objects, saving nothing to the database (when possible). Here is a comparison of using FactoryGirl vs. bare domain objects:

FactoryGirl

context '#validate flight dates with FactoryGirl' do
  setup do
    @campaign = FactoryGirl.build(:campaign, id: 1234, flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,28))
  end
  
  should 'be valid if campaign has the same flight_start and flight_end' do
    assert_true @campaign.valid?
  end
  
  should 'be invalid if flight_end is before flight_start' do
    @campaign.flight_end = Date.new(2014,01,27)
    assert_false @campaign.valid?
    assert @campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
end

 

Bare Domain Objects

context '#validate flight dates with Bare Domain Objects' do
  should 'be valid if campaign has the same flight_start and flight_end' do
    campaign = Campaign.new(name: 'UNICORNS!!!', flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,28))
    campaign.valid?
    assert_false campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
  
  should 'be invalid if flight_end is before flight_start' do
    campaign = Campaign.new(name: 'UNICORNS!!!', flight_start: Date.new(2014,01,28), flight_end: Date.new(2014,01,27))
    campaign.valid?
    assert campaign.errors.full_messages.include?('Flight start must be earlier than campaign flight end date')
  end
end

Not so different, right? Takes less time since I’m not writing to the database and the only major difference is that I don’t assert that the object is valid. Instead I check to see if it is adding my error message. This helps simplify tests, even for more complicated objects.

Test Unit + Shoulda

Do you use Thoughtbot’s shoulda matchers? If not you should. Super handy for testing Rails applications. However, I did ran into an issue that I banged my head on the wall for an hour before noticing the very simple problem.

I was adding some tests to a controller, and, in this case, they were already written but commented out, so I was just editing them and getting them to work. We use the shoulda matchers and the accompanying context blocks to organize our tests, but the tests I was editing were just using basic Test Unit syntax (test “this is what i’m testing” do). I kept getting an ArgumentError (1 for 2). However, the function I was testing only had one argument, so I couldn’t figure out why it was asking for a second. The issue ended up being that the tests were within a context block and context blocks do not work with Test Unit. Once I converted it to should “this is what I’m testing” do, it worked perfectly.

Simple mistake, but easy to miss if you are trying to fix up legacy code.

Git Rebase

For a while I was staying away from git rebase because I kept getting crazy errors and commits that weren’t mine whenever I tried to rebase. No more!

# rebase!
git checkout branch-i-want-to-merge
git log
git rebase -i HEAD~6
git log
git rebase old-branch
git checkout old-branch
git merge branch-i-want-to-merge

Command by command:

I have a branch called branch-i-want-to-merge that has 6 commits. I have a master branch called old-branch that I want to merge my branch into, but not before cleaning up the commit history (does everyone need to know that I forgot an s?).

I have branch-i-want-to-merge checked out. I double check my number of commits by doing a git log and counting them. I see 6, so I do a git rebase -i HEAD~6. After this, I do a git log again to verify that I only have 1 commit.

Now I want to make sure my new branch has all the commits from the old branch, so I do git rebase old-branch. Success!

Final steps: I check out old-branch, then do merge in my new branch with a git merge branch-i-want-to-merge. All done! That wasn’t so hard, right?

Testing Private Controller Methods in Rails

class FooController < ApplicationController
  private
  def is_awesome?(unicorns)
    unicorns.awesome == 'DEFINITELY'
  end
end

class FooControllerTest < ActionController::TestCase
  should 'return true when unicorns are awesome'
    @unicorn = Unicorn.new(awesome: 'DEFINITELY')
    assert_true @controller.send(:is_awesome?, @unicorn)
  end
end

Yesterday I wrote two private methods to a controller that I was working on and, failing on doing TDD, I wrote the tests today. I actually ran into a few issues because, originally, I was not passing anything to my methods. The methods were just taking instance variables that were defined in the new method that was calling my functions. Works in practice, but when I wanted to test just these methods, I could not get them to read the instance variable without calling the whole new method. End result after trying a few other things? Just passing the variable to the private method (as seen above). Still works when called in the new method, but is also much easier to test. Success!