Yesterday I found out I had made a major boo-boo in setting up an ActiveRecord::Association.
Imagine a “Widget” model that is composited of serveral other fields. You might think to yourself.
“An Widget has a SKU ( housed in table ‘skus’ based on model SKU ), a widget has a color, etc.”
You then might model your code such that
Widget < ActiveRecord::Base has_one :sku has_one :color end
SKU < ActiveRecord::Base belongs_to :widget end
This is wrong.
You must think in terms of the most “atomic” element. What’s the relationship of a SKU? A SKU “has one” product to which it is applicable. You see, what you’ve done above is absolutely reverse of the way it should be.
Think this way:
SKU < ActiveRecord::Base has_one :widget end
And then just add the mirror entry, for completeness
Widget < ActiveRecord::Base belongs_to :sku end
You can see this explained in the Rails API:
class Employee < ActiveRecord::Base has_one :office end class Office < ActiveRecord::Base belongs_to :employee # foreign key - employee_id end
If you find yourself using the primary key of the composite entity to find something in the the constituent table or getting into weird sorts of problems with .create() or find yourself thinking that you may need to implement something like (although it is pretty cool):
$ irb irb(main):001:0> class K irb(main):002:1> end => nil irb(main):003:0> k1 = K.new => #<k:0xb7fc1788> irb(main):004:0> k2 = eval('K').new => #<k:0xb7fb8094> irb(main):005:0> k3 = Object.const_get('K').new => #<k:0xb7fb1474>
The real difficulty here is with how English speakers construe the transitivity of the phrase “has one”. Does this mean:
- X is a superior containing entity i.e. “contains” (“The happy meal has one hamburger and one toy”)
- X is uniquely assigned in a relationship (“The parolee has one parole officer”)
The word “relationship” in the second bullet is the use of “has_one” that Rails uses the phrase “has_one” to signify.