Вопрос

I'm trying to think in a business model very similar to the one described here, using STI.

class Person < ActiveRecord::Base
   # identified by email
end

class Owner < Person
end

class Customer < Person
end

class Employee < Person
end

class Store < ActiveRecord::Base
   belongs_to :owner
   has_many :customers
   has_many :employees
end

The classes above describe what I intend to do. The problem here is that a Employee can never act as a Customer, and hire the services provided by the store he works, or even another store, unless a new record is created to represent the same person acting as the a different role in a different context. That is not very DRY, but I don't know if there is a better solution.

Is there? Anyone has any suggestion on how I could resolve this issue?

Thank you very much.

Это было полезно?

Решение

Being an owner (note that there may be several for a given store and one person may own several stores) is not part of a person's identity, it is a relationship between a person and store so subclassing isn't really appropriate here. Similarly for being a customer or employee.

This leaves us with five components:

  1. People.
  2. Stores.
  3. The "person owns a store" relationship.
  4. The "person is a customer of a store" relationship.
  5. The "person is an employee of a store" relationship.

All three relationships are, realistically, many-to-many. Also note that there's STI anywhere in sight; this is a good thing, STI is almost always (IMO) a mistake so you should start questioning your data model and your judgement as soon as it shows up. STI does have its place of course but you should think hard to justify it whenever it comes up.

This leaves us with two fairly simple models (Person and Store) and three many-to-many relationships between people and stores. The standard ways of modelling many-to-many relationships with ActiveRecord are has_many ... :through and has_and_belongs_to_many. If you need to work with one of the person-store relationships as a separate entity (such as an employee with an employee number, hourly rate, tax records, ...) then you'd probably want has_many :through; if you only need the association then has_and_belongs_to_many would probably work.

Some references:

Другие советы

Actually, it is DRY from a code perspective. I actually work on a very similar project using STI where we have users, managers, and administrators, and there must be three records for each in the database. This is DRY from a Rails perspective because each of those records has their own unique attributes, methods in their own classes, etc. but share common code from a similar model to what you call Person. I actually think this is a good way to do it if you're using STI.

An alternative would be to have common code in a module which you could include in each of Customer, Employee, and Owner.

Another alternative (most likely what I would do if starting from scratch) would be to have a single Person table and use roles, using cancan and maybe even rolify. This way you have one class you're dealing with called Person where an instance of Person can have one or many roles, such as customer, employee, or owner.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top