modeling values with units of measure

I’m working on a Rails 3 app that requires a few fields that can be given in multiple units of measure, e.g. miles, kilometers, etc. for distances, miles-per-hour, meters-per-second, etc. for speeds, and so on. I’m curious how others have modeled these types of compound datatypes in Rails. Some requirements that make it interesting:

  • the original value and unit as entered by the user should be saved for each field value

  • I have multiple fields on one object that have units associated with them

  • I need to be able to total/average/min/max fields independent of their individual units (e.g. in metric)

I considered creating a separate UnitValue class (with value, unit, and metric fields) and referencing instances of this class from my main class, but it doesn’t seem to quite fit. The most logical association would be a “has_one” on the main object, but this would require me to add a “belongs_to” for each use of the UnitValue class elsewhere in my models, which is ugly. I could also flip the 1-to-1 association around, but using “belongs_to” on the main object doesn’t seem quite right, either, and I’d still need multiple “has_one” associations on the UnitValue class, even though this wouldn’t require separate database columns.

What I’d really like is to have my UnitValue object flattened/embedded into the main object table as multiple fields, but I’m not sure if that’s possible in Rails at all. Anyone have any advice on the right direction to take here?

Dustin

I'm working on a Rails 3 app that requires a few fields that can be given in multiple units of measure, e.g. miles, kilometers, etc. for distances, miles-per-hour, meters-per-second, etc. for speeds, and so on. I'm curious how others have modeled these types of compound datatypes in Rails.

I haven't done this in Rails, but I've done somewhat-similar things in C++. There, I made a set of classes including Unit (e.g. meter, joule, etc.) and Measure (e.g. 3 meters, -12.3 joules, etc., a combination of a numeric value and a reference to a Unit), which is what I think you mean by UnitValue. Units could be either "base", or defined in terms of a scaling or combination (product or quotient) of other Units. Under the hood a Unit had a list of base Units it depended on (each with a power), plus a scale factor (usually not used except for metric/English conversions).

I think you're on the right track with creating such classes. Your Units are probably simple and constant enough that they don't need to be database-backed. I'd still have an id data-member on them though, for easy handling via AR-type methods. Have the user enter the value in a textbox and choose the unit from a dropdown list (collection_select), which determines the unit_id in the form. You can have a has_one if you like, for convenience (myMeasure.unit), but you don't need a belongs_to -- after all, each Unit is likely to be referenced from many UnitValues.

What I'd really like is to have my UnitValue object flattened/embedded into the main object table as multiple fields, but I'm not sure if that's possible in Rails at all.

Depending on what you mean, that may be exactly what I describe above. Am I close?

-Dave

I appreciate the reply about to implement the Unit and Measure classes (as you call them). I’m already pretty clear on how I want to handle the values with units themselves, my questions is more about how best to use these Measure instances in a Rails model: storing “unit-ed” values for many different fields, in a form that preserves the original values and units, and allowing for summary calculations (i.e. in a cached, shared unit like metric).

My concern is that both 1-to-1 associations (belongs_to and has_one) require the inverse association to be declared on the other side to work correctly (unless I’m wrong about that). This class is more of a data type than a full-fledged model class, so having to update it with a bogus back-association every time I use it in a new field elsewhere in my main model classes seems like the wrong approach.

What feels right is something like MongoDB’s concept of an embedded document, since these Measure objects are really just compound values that only ever make sense within the context of a given model instance. I can’t use Mongo on this project, however, so I’m curious how folks would tackle this problem in ActiveRecord.

Dustin