Snippets

After a spirited bout with rubygems… I have these:

gem list -d gem_name
gem uninstall --install-dir ~/.gem/ruby/1.8 gem_name -a

The first one describes a gem, including the location in which each version is installed. The second will uninstall all versions of a gem from the specified location.

I fought hard for those.

Advertisements

Object Mother Testing Pattern in Rails

Over the years I was working in Java at CGI, I became used to the Object Mother pattern of test setup. Despite the fact that it can break down when objects and their relationships get complicated, it is something that works quite well on smaller projects. At CGI we implemented it like this:

  • One factory per type of object being created
  • Each factory has a createNewValid method that creates a valid object that can be saved to the database. This method does not persist the object.
  • Each factory also has a createAnonymous method that calls createNewValid and then saves the object.

Rails has a number of plugins that do something similar, but object_daddy is the closest to what I was looking for. It follows the same pattern, calling the creation methods spawn and generate instead. It also allows you to customize the look of a valid object by letting you pass in a block that can modify the object’s state. This eliminates a huge problem with our implementation at CGI, where we had hundreds of slightly different createNewValid and createAnonymous methods depending on the scenario we were trying to set up.

Unfortunately I had a couple of problems with object_daddy. The first is that the generate method saves the object before it yields to a passed in block. Thus, when you call User.generate { |u| u.name = ‘Fred’ } you get an object with a name of Fred, but that name is not yet persisted. That was a minor issue, though.

I also had a problem when I tried creating multiple objects with object_daddy within the same setup. I would get an error stating that attributes had already been added for a class, and couldn’t figure out what the heck was going on. It could be just me (probably is), but I found the source code very hard to follow for something that should be pretty simple. Since I’m new to Ruby, I figured I’d just try doing it myself from scratch and maybe learn something in the process.

Enter object_mother. Right now it’s just about as basic as can be. I can think of numerous ways to improve it, but for now I’m pretty happy. Here’s the source in it’s entirety:

module ObjectMother
  class Factory
    @@index = 0
    def self.spawn
      raise 'No create method specified'
    end
    def self.populate(model)
      raise 'No populate method specified for ' + model.to_s
    end
    def self.to_hash(model)
      raise 'No to_hash method specified'
    end
    def self.unique(val)
      @@index += 1
      val.to_s + @@index.to_s
    end
    def self.unique_email(val)
      user, domain = val.split('@')
      unique(user) + '@' + domain
    end
    def self.create
      obj = spawn
      populate(obj)
      yield obj if block_given?
      obj
    end
    def self.create!(&block)
      obj = create(&block)
      obj.save!
      obj
    end
    def self.create_as_hash(&block)
      obj = create(&block)
      to_hash obj
    end
  end
end

All the major concepts are there; create equals createNewValid and create! is the same as createAnonymous. There’s also a create_as_hash method for converting a valid object to a params hash when you’re doing post :create type stuff in functional tests. Currently, you utilize the Factory by sub-classing in your rails app somewhere (I’m just using test_helper.rb for now). Here’s an example:

class AreaFactory < ObjectMother::Factory
  def self.spawn
    Area.new
  end
  def self.populate(model)
    model.name = unique('SW')
    model.city = CityFactory.create!
  end
end

The spawn method just creates a blank instance of the class each individual factory deals with and could definitely be inferred (baby steps, I’ll get to that once the annoyance factor gets higher). Overriding populate is where the attributes of a valid model object are set.

Overall, this is really just what I wanted, and the basic code is only a few simple lines of ruby. I’ll add some smarts in eventually (ie; inferring the class to spawn, creating hashes automatically, giving the user a default place to put Factories, making sure that passing blocks actually works), but for the time being I’m pretty happy.

Just Be Honest and Tell the Truth

I just read Ron Jefferies latest post entitled My Named Cloud is Better Than Your Named Cloud and it got me riled up enough to post something I’ve been meaning to write about for at least a couple of years. His post touches on the point I’d wanted to make, but doesn’t quite say it as simply as I think it can be said. Here’s what I’m thinking:

If we could just always be honest with ourselves, as people, team members and organizations, software development wouldn’t be that hard.

There. Simple. Think about it for a second. All this stuff that we label and group together under methodologies and processes is really there so that we can do One Thing. This one thing, I’m assuming, is usually to create software that fulfills a need.

Let’s pretend that a software team has been assembled to create an application that fulfills such a need. They’ve chosen to use the XP methodology while writing this application. I’ll go through some of the tenets of XP and run them through my honesty filter:

  1. Pair programming: The team realizes that people will come and go on a project for good (quit, fired, etc), or for short periods of time (maternity leave, vacation, illness, etc). They want to minimize the risk, so they make sure everyone is familiar with every piece of the code base. They also realize that sometimes even the best developers do stupid shit for no good reason, and believe that having two sets of eyes on the screen at all times will lessen the likely hood of this happening.
  2. TDD: The team realizes that writing software is hard, and that stuff that worked last week will have to be changed this week. Since they want to ensure that stuff they worked on earlier still works when they make these changes, they write tests, and ensure that no code gets checked in unless all the tests are passing. They also hope that these tests provide some form of documentation to any developers (and perhaps users/clients) that may come later or who never worked on the feature originally.
  3. Incremental design: The team realizes that there are unforeseen forces that may threaten a project at any given time. A big project entails a large amount of risk for both clients and developers. If features can be developed in incremental fashion, hopefully in an order representing the importance of each feature, then risks can be mitigated. The team is always working with a usable application, so that if something comes up that stops the project, at least the client will have something to work with.

Now obviously there is more to XP than what I’ve listed. The point is that those three things exist to handle a need that most teams, if they are really honest with themselves have:

  1. Knowledge transfer. Nobody wants to have to rely on one person to get something done. Sooner or later, this always bites us in the ass. Pairing is one way to handle this.
  2. Developed features continue working. Nothing is more frustrating (to users and developers) than having something that used to work perfectly stop working. Testing is one way to handle this.
  3. The need to guarantee that something will come out of all the money we’re spending. What happens if the development shop you’ve contracted goes bankrupt before they’ve finished your application? Incremental design is one way to handle this.

Listen. We have methodologies and processes for a reason (I hope). Some of these processes may work for you. However, maybe only some parts of a process work for you. The point is, it’s not about the process. If you can understand why you’re using a particular piece of a process, you can assess whether it’s useful for your team. Who cares whether you’re doing XP, Scrum, Lean, Kanban, Waterfall, or Hack ‘n’ Slash. Those are just names. Identify your pain points, problems, worries, etc, and try to fix them. Honestly.

Rails, Nested Forms and collection_select

I spent a bit of time on this tonight and thought I’d post about it.

I have a Property model that has a has_one relationship with an Address model. I want to be able to CRUD these two objects as one single entity, however. Luckily, nested forms were recently introduced into Rails 2.3.2 and they seemed like they’d simplify the whole process. Which they did once I put everything together. First, my models:

class Property  true
end

class Address < ActiveRecord::Base
  has_one :property
  # the Address model has a :city string column that will get populated from
  # a drop-down list in our view
end

This is the basic stuff that any tutorial on nested forms in Rails will tell you about, with the exception of creating a default instance of the address in the property constructor. This is most likely specific to the has_one case. Most of the examples I have seen deal only with has_many, where behind the scenes rails creates an empty list and we’ll never end up with nil reference errors in our view. This was the first issue I had to solve. Now let’s move on to our new.html.erb view:


  
  

The trick here is to make sure you qualify the collection_select for cities with the specific fields_for instance. If you don’t, the form will render and appear to be ok until you post to the create action or view the generated source:

notice how I've removed the af. qualifier on collection select, and added in a new parameter :address. This is how most tutorials show you how to use it The problem with this is that the rendered html does not generate properly for our nested form scenario

Once you qualify the collection_select helper properly, you should get generated html that looks like this:

City
        Lethbridge

Now when you post the form, Rails nested form magic just works. My controller looks just as you’d expect (ie; no different than the non-nested form scenario)

  def create
    @property = Property.new(params[:property])
    respond_to do |format|
      if @property.save
        flash[:notice] = 'Property was successfully created.'
        format.html { redirect_to(@property) }
      else
        format.html { render :action => "new" }
      end
    end
  end

Hopefully I’ve explained this properly. Feel free to ask questions in the comments if I haven’t.

Extending clearance

I thought I’d try using clearance to handle authentication on the Rails app I’m developing. It seems pretty nice and basic, but I wanted to add a :name property on the user model (not for authentication, just for display purposes).

Once I’d created a migration to add the new column to the user model, I needed to add the field on the corresponding view so it could actually be input by a user. Since clearance is installed as a vendor gem/engine (still not sure what the difference is) the view files are located in the vendor directory. I figured updating these files wouldn’t be good, since they’d be overwritten if I ever had to update and unpack the gem.

It turns out all I had to do was copy the view files into my app under the views/user/ directory. I could then modify the files at will, and they would be used by Rails instead of the vendor files. One other gotcha was to make sure to add the attr_accessible :name declaration in my user.rb file (so Rails can do a mass assignment of the posted form items). My user.rb ended up looking like this:

class User < ActiveRecord::Base
  include Clearance::User
  has_many :properties
  attr_accessible :name
end

Rails Functional Testing Gotcha

I just started writing my first real Rails app this weekend, and as I struggle along I thought I’d document where I’m tripping up.

My first order of business is to write functional tests on my controllers and views. For some reason I thought I’d give the tests (which inherit from ActionController::TestCase) descriptive class names like PropertiesDashboardTest instead of PropertiesControllerTest. I had tests running and passing before I renamed the test class, but then started getting this error:

RuntimeError: @controller is nil: make sure you set it in your test’s setup method.

It took me a while to realize that Rails auto-instantiates a controller instance based on the test name when you inherit from ActionController::TestCase. Since I don’t have a controller named PropertiesDashboard.rb, Rails can’t set one up in the test for me. Of course I’m doing this test-first, so a controller doesn’t even exist at this point. That also explains why my existing test started failing when I renamed it.

New Ride

I found my new ride for the summer, a one or two year old Cannondale cyclocross bike! Paid $850 for it, which almost feels like stealing. I can’t wait for spring.