Handling multiple Account Types

Hello Guys,

I’m doing some research on how to handle multiple account types. In our app, we will have two types of accounts. Parents and Schools. These accounts will never change types, for example a Parent becoming a School.

Schools will have different relationships than Parents, but both will have the ability to login into their accounts (different UIs for both models).

I’m thinking in going with one Account per model, and have an account type to differenciate between Parents and Schools

class Account < ActiveRecord::Base
  # account_type in ["parent", "school"]
end

class School < ActiveRecord::Base
  has_many :accounts, as: :user
end

class Parent < ActiveRecord::Base
  has_one :account, as: :user
end

Then the idea is to use Pundit to handle authorization

What do you think?, does this sounds like a good approach?

Thanks!

1 Like

There isn’t a single right answer to this, and the best approach will likely depend on your particular application. Your approach is definitely viable, but you might want to go with something a little different depending on your needs.

Consider some of these questions:

  1. Do you expect that school accounts will have various roles (like teacher, administrator, etc.?). If so, there might be a relationship you want to have that applies to school accounts, but not parent accounts.

  2. Do you expect someone to be able to have both a parent account and a school account (i.e. a teacher that is also a parent?) If so, your authorization library will need to be smart enough to distinguish accounts based on something more than the email address (or, you’ll have to use separate tables for each kind of account.)

  3. Do you expect additional attributes for school accounts vs. parent accounts? For example, perhaps a school account needs a title (like Principal or Teacher or Coach), whereas a parent would have no such title.

At the very least, I would introduce one more model called SchoolUser to separate Account from School like this:

class Account < ActiveRecord::Base
  belongs_to :user, polymorphic: true # Either a `Parent` or a `SchoolUser`
end

class SchoolUser < ActiveRecord::Base
  has_one :account, as: :user

  # Has attributes that a parent doesn't have like `title`, `employment_year`, etc.

  # Also might have associations that a parent doesn't have:
  has_many :school_user_roles, through: :school_user_role_assignments
end

class School < ActiveRecord::Base
  has_many :school_users
end

class Parent < ActiveRecord::Base
  has_one :account, as: :user
end

For my applications I generally go a little further and put different “kinds” of users in completely separate tables. This allows various relationships to be more explicit (i.e. no STI and no polymorphic relationships):

class SchoolUser < ActiveRecord::Base
  # this model can login
  belongs_to :school
  has_many :school_user_roles, through: :school_user_role_assignments
end

class Parent < ActiveRecord::Base
  # this model can login too
end

There are definitely appropriate situations for STI and polymorphic associations, but you sacrifice a little bit of clarity when you use them.

One downside to using separate authentication tables for different kinds of users is that your application might end up with more redundancy, if you’re not careful.

At the end of the day, try an approach and see how it works for you. You can always change it later.

1 Like

Thanks for your answer @naw. Having separated table is what I had in mind, and we won’t have cases where an account may have multiple types (both parent and teacher), in this case, we will require separate accounts.

I’ll follow your advice and implement this approach and see how it goes.

Thanks again!

In the end, we implemented this as a polymorphic association between User and Parents/Schools.

class School < ActiveRecord::Base
  has_many :users, as: :organizable
end
class Parent < ActiveRecord::Base
  has_one :user, as: :organizable
end
class User < ActiveRecord::Base
  belongs_to organizable, polymorphic: true
end

User is the one that has email/password and can log in, and given the organizable_type key; we handle if it’s a School or a Parent. All worked pretty well, and it was pretty straightforward to implement.