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

On Tue, Jan 17, 2012 at 00:06, Dustin F. [email protected]
wrote:

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


Dave A., President, Dave A. Software Engineering and Training
Ruby on Rails Freelancing (Northern Virginia, Washington DC, or Remote)
DaveAronson.com, Codosaur.us, Dare2XL.com, & RecruitingRants.com (NEW!)
Specialization is for insects. (Heinlein) - Have Pun, Will Babble! (me)

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