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

class Node < ActiveRecord::Base

  inherited_attribute :value

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?

Labeling Rails Enums

Rails 4.1 introduced ActiveRecord Enums, a handy little feature that lets you store an integer in a database column, but use symbols or strings in your code.  Until today, I’ve been presenting these in select boxes with code like this:

This generates a perfectly acceptable select box if you don’t need internationalization and the enum names you’ve picked are good enough to present to the user.  If thats not the case, or you to change the presentation without changing the code, a new helper method leveraging Ruby’s internationalization (i18n) features can be a good approach.

Keep reading for how I changed the presentation of enumerations in a drop down without changing my models or renaming the enumeration names.

Here is how we can provide alternate labels for some of our drop down values.

First, create a new helper that will pass each enumeration name through i18n to perform a label conversation

Second, change your form to call the helper

Third, provide the translations.

Before translation:

After translation:

A few notes:
  • If the translation is missing, the code’s default is to fall back to the titleized text.  If you want to omit options where the translation is missing,  You can modify the methods to call enum_to_translated_option with a default of blank and the blank options will be removed from the select.
  • enum_to_translated_option is useful in a show template.  
  • It may be useful to sort the options after translation.  That is an easy addition to the helper.

Is this useful for you?  Is there a better way?  Let me know!

Removing milliseconds in JSON under ActiveRecord 4.0

Rails 4.0 introduced a small bug in JSON generation with this pull request. The output format for times (ActiveRecord::TimeWithZone) in JSON changed to include milliseconds. Sounds good right? Well, not if your API clients crash trying to parse milliseconds. Unfortunately, Rails 4.0 didn’t provide a configuration option for the timestamp precision in JSON output. What is a programmer under the gun to do? Upgrade to Rails 4.1 or get out your monkey and your patch and get to work?

First, lets see the bug in action. This test passes in Rails 3.2.15, but fails in Rails 4.0.4:

Simple enough. This is easier to see if you’ve got a Rails app:

Rails 4.1 adds a configuration option to default the time precision. In that version, you can set ActiveSupport::JSON::Encoding.time_precision = 0. However, if you are on Rails 4.0 for a bit, you can monkey patch AtiveSupport::TimeWithZone to go back to the Rails 3.2 implementation:

Normally, it seems the Rails team does a better job than this. Fortunately, with Ruby we’ve got the openness to go back to the old behavior in a pinch.