POSTS
[Rails] Associations
BlogYesterday 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
And accordingly
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.