title: Rails models: has_many_and_belongs_to_one
body: <p>I have two models with a has_many association.  However, from the "many", only one is primary.  Here's one way to design it:</p>
  
  <h2>Approach #1</h2>
  
  <pre><code>class Person &lt; ActiveRecord:Base
    has_many :address
  
    def find_primary
      self.address.where('is_primary = ?', "true").first
    end
  end
  
  class Address &lt; ActiveRecord:Base
    belongs_to :person
    attr_protected :is_primary
  
    def make_primary
      self.person.address.each { |a| a.update_attribute(:is_primary, false) }
      self.update_attribute(:is_primary,true)
    end
  
    def is_primary?
      self.is_primary
    end
  end
  </code></pre>
  
  <p>I don't like how <code>make_primary</code> is O(n) for number of addresses of that person.  It could also be a problem in a multi-threaded environment (i.e. passenger, right?).  Maybe there's an optimization for <code>make_primary</code> that could work better for approach #2?</p>
  
  <p>Also, there could easily have hard-to-spot bugs that allow multiple addresses to be primary.</p>
  
  <h2>Approach #2</h2>
  
  <pre><code>class Person &lt; ActiveRecord:Base
    has_many :address
    belongs_to :primary_address, :class_name =&gt; 'Address', :foreign_key =&gt; :primary_address_id
  end
  
  class Address &lt; ActiveRecord:Base
    belongs_to :person
    has_one :person_as_primary, :class_name =&gt; 'Person', :foreign_key =&gt; :primary_address_id
  
    def make_primary
      self.person.primary_address = self
      self.save!
    end
  end
  </code></pre>
  
  <p>Aside from avoiding the multi-threading and O(n) issues, this approach makes <code>find_primary</code> unnecessary, since it's simply <code>self.primary_address</code>.</p>
  
  <p>However, the concern here is that there's no guarantee that </p>
  
  <pre><code>[person, nil].include?(person.primary_address.person_as_primary)
  </code></pre>
  
  <p>Here are my questions:</p>
  
  <p>1)Are there additional advantages/disadvantages that I failed to mention?</p>
  
  <p>2) What other approaches should I consider?  In particular, are there any that don't raise any of the above issues?</p>