Inheriting Attributes in a Tree Data Structure

I just published a new gem, inherited-attributes, for Active Record that works with the Ancestry gem to provide a tree data structure the ability to inherit attributes from their parent node, or farther up the tree.  We’ve been using this technique for a long time to support configuring our multi-tenant application.

Once the gem is installed, its very simple to configure:

ActiveRecord::Schema.define do
  create_table :nodes, :force => true do |t|
    t.string :name
    t.string :value
    t.string :ancestry, :index => true
  end
end

class Node < ActiveRecord::Base
  has_ancestry

  inherited_attribute :value
end

From there, you can access the effective attributes which look up the tree ancestry to find a value to inherit.

root       = Node.create!
child      = Node.create!(:parent => root, :value => 12)
grandchild = Node.create!(:parent => child)

root.effective_value       # nil
child.effective_value      # 12
grandchild.effective_value # 12 -- inherited from child

There are more options and examples in the gem, including has-one relationships, default values and support for enumerations.

We’ve found it helpful and writing a gem made this code much easier to test.  What code do you have that would be easier to test as a gem or would be useful to others?

How to write a simple Rails gem

Today, I wrote my first Ruby on Rails gem.  It was a very simple refactoring of our code that I undertook when I needed to add the same functionality to a new model and I decided to do it as a gem instead of keeping it within our project.  I wanted to see how it worked and this is what I ended up with.  You can follow the Rails Guide, but it didn’t cover everything I wanted to do.

Create a repository for your gem.

You can do this on github, like I did for my gem, locally, or somewhere else.  

Create a skeleton gem

The rails guide for creating a plugin has this, but the details in the guide are thin.

Rails 3.1 ships with a rails plugin new command which creates a skeleton for developing any kind of Rails extension with the ability to run integration tests using a dummy Rails application.

I used this to create a skeleton for my plugin:

This creates a skeleton gem with a dummy rails application you can use for testing your gem.

Switch to rspec

I’ve used rspec for all my rails testing and I wanted to use it with my new gem as well.  However, the generator creates a test-unit dummy application out of the box.  This StackOverflow question had a good answer that I used to switch from test-unit to rspec.

  1. Add rspec as a development dependency in your gemspec
  2. Bundle Install
  3. Convert from test-unit to rspec
  4. Modify spec_helper.rb with code taken from test_helper.rb
  5. Run the tests
  6. Commit the skeleton gem to source control

Author your gem

At this point, you have a skeleton gem that you can use to write your code.  The gem I wrote added some behavior to ActiveRecord models, so I started out by generating some models in the dummy rails application located in spec/dummy and using test-driven development to build my gem.  

Try it with a real project

The tests you author along with your gem are very helpful, but a time will come when you want to try your gem on your local file system with a real project.  You can include a gem from the local file system with this in your gemfile:


Squash your commits

When you’ve got your gem working and you are ready to publish it, you may want to squash all your commits to the repository into a single commit.

Take a look at http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html or search the web on how to squash multiple commits to a single commit, or try it with git rebase -i