0
votes

I have a base class called User and it has 2 subclasses named Manager and Creator. I have implemented Single Table Inheritance for User, Manager and Creator models.
There are 2 other models named Project and Bug.

class User < ApplicationRecord
end

class Manager < User
end

class Creator < User
end

class Project < ApplicationRecord
end

class Bug < ApplicationRecord
end

The associations I want to have are

  • A Project can have many Users
  • A Manager can have many Projects
  • A Creator can create many Bugs

I understand the relations but I am unable to understand where to put the associations(for the User and it's subclasses).
For example
For the association: A Creator can create many Bugs

class Creator < User
   has_many :bugs
end

Where do I put the other side of the association declaration? Do I write it inside the User class or the Creator class?
i.e

class Bug < ApplicationRecord
   belongs_to :user
end

or

class Bug < ApplicationRecord
   belongs_to :creator
end

Which one is the right way to do it?
The bottom line of the question is:
In Single Table Inheritance do I make associations(of other models) with the parent model or the child model?

1
User, Manager, and Creator all look like roles held by a Person. I don't know anything about your domain, but STI would not be my go-to approach here.jvillian
what do you suggest instead of STI? I am supposed to have all these entities, as a part of my domain models.Masroor

1 Answers

1
votes

In response to your comment, below is a potential way to model the associations you enumerate using only User, Project, Bug, and ProjectUser without STI.

A simple way to model A Creator can create many Bugs might be something like:

class User < ApplicationRecord
  has_many :bugs, foreign_key: :creator_id
end

And for your Bug model:

# == Schema Information
#
# Table name: bugs
#
#  id                     :integer          not null, primary key
#  creator_id             :integer
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
class Bug < ApplicationRecord
  belongs_to :creator, class_name: 'User'
end

In this case, the role is implied by the association definition, but you don't have an explicit Role model. So if you have an instance of @user, you could do something like:

@user.bugs.create bug_attributes

If you have an @bug, then you can do:

@bug.creator

...and get back the User that created the Bug.

Similarly, to model A Manager can have many Projects, you could do something like:

class User < ApplicationRecord
  has_many :bugs, foreign_key: :creator_id
  has_many :managed_projects, class_name: 'Project', foreign_key: :manager_id
end

# == Schema Information
#
# Table name: projects
#
#  id                     :integer          not null, primary key
#  manager_id             :integer
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
class Project < ApplicationRecord
  belongs_to :manager, class_name: 'User'
end

Again, the role is implicit to the association definition. And, with @user, you can do:

@user.managed_projects.create project_attributes

To model A Project can have many Users (assuming that a User can belong to many projects), you could use a ProjectUser model that might look something like:

# == Schema Information
#
# Table name: project_users
#
#  id                     :integer          not null, primary key
#  project_id             :integer
#  user_id                :integer
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
class ProjectUser < ApplicationRecord
  belongs_to :project
  belongs_to :user
end

Then in your Project, you could do:

class Project < ApplicationRecord
  belongs_to :manager, class_name: 'User'
  has_many :project_users
  has_many :users, through: :project_users
end

And in your User, you could do:

class User < ApplicationRecord
  has_many :bugs, foreign_key: :creator_id
  has_many :managed_projects, class_name: 'Project', foreign_key: :manager_id
  has_many :project_users
  has_many :projects, through: :project_users
end

Now you can do things like @project.users and @user.projects.

Depending on your domain and use cases, you might want to make Role an explicit class. But, that's a whole other kettle of fish.