tipugin
tipugin

Reputation: 259

Rails and multiple profiles

I have the app, where user can have one of several different profiles. Some of profile data are always the same (like first and last name, gender etc). Other fields may vary (for example, doctor can have license number and text about himself, while patient can have phone number etc).

I found approach, that fits pretty well, but still have some doubts. The point of my approach looks like this:

  1. User model contains a lot of system-specific data, controlled by Devise and has_one :person

  2. Person model contains common profile data and belongs_to :profile, :polymorphic => true

  3. Doctor/Patient/Admin/etc contains more specific profile data and has_one :person, :as => :profile

With this approach i can simply check in Person model:

def doctor? self.profile_type == 'Doctor' end

But there is the few things doesn't give me a rest.

First one is performance. This approach requires a lot of additional joins. For example, for reading doctor's license number, first/last name and email at the same time it will generate 2 additional joins.

Second one is different ids for profile-specific model (i.e. Doctor) and for Person/User models. There will be situations, when user with ID=1 will have Patient relation with different ID, but it would be logical to have same ID for all this associated models.

Maybe you guys will see any more pitfalls in this approach? Is there any better solution for my situation?

Upvotes: 0

Views: 433

Answers (1)

tadman
tadman

Reputation: 211600

You've got four basic patterns you can use here that might work.

Omnirecord

In this model you have all the possible fields in a single record and then use STI to differentiate between profile types. This is the simplest to implement but looks the most messy as few people will have all fields populated. Keep in mind that NULL string fields don't take up a lot of database space, typically one bit per column, so having a lot of them isn't a big deal.

Optional Joins

In this model you create a number of possible linkages to different profile types, like doctor_profile_id linking to a DoctorProfile, patient_profile_id linking to a PatientProfile, and so forth. Since each relationship is spelled out in a specific field, you can even enforce foreign key constraints if you prefer, and indexing is easy. This can come in handy when a single record requires multiple different profiles to be associated with it, as in the case of a patient that's also a doctor.

Polymorphic Join

In this model you link to a specific profile type and profile id using the :polymorphic option, much like you've suggested. Indexing is more complicated and foreign keys are impossible. You're also limited to having one and only one profile. These tend to work as a starting point but may prove to be trouble down the road when you get a doctor + patient requirement.

Key/Value Store

In this model you abandon all efforts to organize things into singular records and instead build an associated ProfileField and ProfileValue table. The ProfileField identifies what fields are available on what kinds of profiles, such as label, allowed values, data type and so forth, while the ProfileValue is used to store specific values for specific profiles.

class User < ActiveRecord::Base
  has_many :profile_fields
end

class ProfileField < ActiveRecord::Base
  has_many :profile_values
end

class ProfileValue < ActiveRecord::Base
  belongs_to :user
  belongs_to :profile_field
end

Since this one is wide open you can allow the site administrator to redefine what field are required, add new fields, and so on, without having to make a schema change.

Upvotes: 3

Related Questions