2012-04-15

Bi-directional use of class_name in ActiveRecord associations

I recently wanted to use ActiveRecord's association syntax on two models, called Proposal and Period. To add clarity, I wanted the Proposals to be called struck_proposals, from the perspective of the Period. And I wanted the Period to be known as struck_on_period from the perspective of the Proposal. While the Rails guide explains how to do this in one direction or the other, it took considerable searching to figure out how to set up a "bi-directional" aliasing like this. Finally, it turned out that there are two ways to do it, seen here.
class Period < ActiveRecord::Base
  has_many :struck_proposals, class_name: 'Proposal'
end

class Proposal < ActiveRecord::Base
  belongs_to :struck_on_period, class_name: 'Period',
    foreign_key: :period_id
end
Or this way:
class Period < ActiveRecord::Base
  has_many :struck_proposals, class_name: 'Proposal',
    foreign_key: :struck_on_period_id
end

class Proposal < ActiveRecord::Base
  belongs_to :struck_on_period, class_name: 'Period'
end
Since either way works, the choice unfortunately seems arbitrary. But I later noticed that it's actually not. Just imagine that you wanted to add an additional type of Proposal, e.g. an executed Proposal. Then a Proposal could belong to a Period in two different ways. But it obviously couldn't have two different columns named period_id. It would have to have a struck_on_period_id and an executed_on_period_id. So the latter implementation is the correct one.

No comments: