Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails model with multiple instances of a single 'has_one" model

I'm trying to make a rails model that contains two different "has_one" attributes of the same class. I feel like there is an easier way to do this, but I can't think of it right now.

So, lets say I'd like to create a wedding model in rails

class Wedding < ActiveRecord::Base
  has_one :groom, :class_name => 'Person'
  has_one :bride, :class_name => 'Person'
end


class Person < ActiveRecord::Base
  attr_accessible :wedding_id

  belongs_to :wedding
end

My goal is to have access to the groom object from the wedding object. (be able to call @wedding.groom.name or whatever) Currently there is no way for the Wedding Model to know which "person" is the Bride and which is the Groom.

Should I be using single table inheretance? Or should I be using foreign keys?

Is there a better way to think of the whole problem?

like image 545
Mike Vormwald Avatar asked Oct 12 '12 02:10

Mike Vormwald


3 Answers

Your associations are backwards for the functionality that you want..

class Wedding < ActiveRecord::Base
  belongs_to :groom, :class_name => 'Person'
  belongs_to :bride, :class_name => 'Person'
end

class Person < ActiveRecord::Base
  has_many :weddings  # who has just one wedding now days???
end

Wedding.find(params[:id]).groom.name

Person.find(params[:id]).weddings.last  # hopefully first also  :)
like image 129
ilan berci Avatar answered Nov 04 '22 04:11

ilan berci


Change Person to Participant, and give it a role attribute. Then you can do

class Wedding < ActiveRecord::Base
  has_one :groom, :class_name => 'Participant', :condition => "role = 'groom'"
  has_one :bride, :class_name => 'Participant', :condition => "role = 'bride'"
end

(Naturally there's no technical reason you need to use Participant instead of Person; it just makes more sense to me that a Participant would have a Role in the Wedding, while a Person is a more general thing. For example, if you wanted to add other roles, you might have a participant with a role of bridesmaid who was the same Person as another participant with a role of, say, caterer.)

like image 28
Jacob Mattison Avatar answered Nov 04 '22 04:11

Jacob Mattison


Depending on how different they will be treated within the domain, there may be nothing wrong with the approach you have taken.

In the event that 'groom' and 'bride' are mostly naming conventions that are generally treated equally, it may be wiser to simply make a has_many :parties relationship and let the Person model determine which is the bride/groom. Perhaps something like this:

class Wedding < ActiveRecord::Base
  has_many :parties, :class_name => 'Person'

  # helper methods to access bride and groom where specifically needed
  def self.groom
    parties.where(party_type: Person::GROOM).first
  end

  def self.bride
    parties.where(party_type: Person::BRIDE).first
  end
end

class Person < ActiveRecord::Base
  attr_accessible :wedding_id, :party_type

  GROOM = 'Groom'
  BRIDE = 'Bride'

  belongs_to :wedding
end
like image 38
PinnyM Avatar answered Nov 04 '22 04:11

PinnyM