Alaina Wilkins
Alaina Wilkins

Reputation: 175

Polymorphic has_many through Associations in Ruby on Rails

I have the following problem, A user can have several professions, more than 10. For example, a user may be a doctor, teacher, and N. Each profession has its own attributes. I could do, Doctor belongs_to User, but if I want to know all the professions of this user I will have to check each row of the User table.

I created the following code

class User < ApplicationRecord
  has_many :jobables
end

class Job < ApplicationRecord
  belongs_to :user
  belongs_to :jobable
end

class Jobable < ApplicationRecord
  has_one :job
end

class Medic < Jobable
end

class Programmer < Jobable
end

But I do not know if that would be the best answer

Upvotes: 5

Views: 74

Answers (1)

jvillian
jvillian

Reputation: 20253

I would think that it would be much easier to do something like:

class User < ApplicationRecord
  has_many :user_professions
  has_many :professions, through: :user_professions
end

# == Schema Information
#
# Table name: professions
#
#  id                     :integer          not null, primary key
#  name                   :string
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
class Profession < ApplicationRecord
  has_many :user_professions
  has_many :users, through: :user_professions
end

class UserProfession < ApplicationRecord
  belongs_to :user 
  belongs_to :profession 
end

You could then create logic to ensure that a Profession is only assigned to a User once.

Then, you could simply do:

@user.professions

And get all the Professions for a User.

You could also do:

@profession.users 

And get all the Users that belong to the Profession.

Based on the edit to your question, you could do something like:

class UserProfession < ApplicationRecord
  belongs_to :user 
  belongs_to :profession
  belongs_to :profession_detail, polymorphic: true
end

In which case you might have something like:

class DoctorDetail < ApplicationRecord
end

And you could do something like:

@user.professional_detail_for(:doctor)

Of course, you would need to implement the professional_detail_for method on the User model which might look something like:

class User < ApplicationRecord 
  has_many :user_professions
  has_many :professions, through: :user_professions

  def professional_detail_for(profession_type)
    user_profession_for(profession_for(profession_type)).try(:profession_detail)
  end

private

  def profession_for(profession_type)
    Profession.find_by(name: profession_type.to_s)
  end

  def user_profession_for(profession)
    user_professions.find_by(profession: profession)
  end

end

That's a little rough, but I imagine you get the idea.

Upvotes: 5

Related Questions