我想创建一个基本模型Person
,其中包含一些与人物相关的属性,如姓名,地址,电话等。一个Person
可以一个或多个以下:
LoginUser
包含登录名,密码,last_login,... CardHolder
包含card_id,last_entrance,... Supplier
只是一个标志,无论该人是否是供应商</ li>
Recipient
只带一个标记,无论该人是否为收件人 Ruby on Rails中是否存在常识或最佳实践设计模式来表示继承?如何在模型和表结构中表示它,以便可以检查Person
是否为LoginUser
并访问相应的字段。
在另一个项目中,我已经与STI合作,但在这种情况下,这不是正确的模式。
答案 0 :(得分:1)
您正在寻找的是反向多态关联。多态关联允许您将一个模型链接到许多不同的模型。 反向多态关联允许您将多个模型链接到一个模型。它们设置起来有点棘手,但是一旦掌握了它就没问题了。
为了实现这一目标,您需要另一个模型作为Person
模型和每个不同角色的中间人。这种中间模型实际上具有多态关联。您的人员模型将has_many
该模型,您的各种角色模型将has_one
。然后使用:through
进行其余必要的关联,这样您的代码就不会有任何不同。快变!
以下是如何使用Person
和CardHolder
模型执行此操作的示例。我正在调用额外的模型Role
,因为这似乎是一个明显的选择:
class Person < ApplicationRecord
has_many :roles
# Reach through the Roles association to get the CardHolders, via polymorphic :rollable.
# Unfortunately, you can't has_one, so you'll have to enforce uniqueness in Role
# with a validation.
has_many :card_holders, through: :roles, source: :rollable, source_type: 'CardHolder'
end
class Role < ApplicationRecord
belongs_to :person
# Here is where our actual polymorphic connection is:
belongs_to :rollable, polymorphic: true
end
class CardHolder < ApplicationRecord
# The other side of the polymorphic connection, with has_one:
has_one :role, as: :rollable
# Get the person via the role, just like the inverse:
has_one :person, through: :role
end
数据库设置如下:
class CreatePeople < ActiveRecord::Migration[5.1]
def change
create_table :people do |t|
t.string :name
# put in whatever other Person columns you need
t.timestamps
end
end
end
class CreateRoles < ActiveRecord::Migration[5.1]
def change
create_table :roles do |t|
t.references :person, index: true
t.references :rollable, polymorphic: true, index: true
t.timestamps
end
end
end
class CreateCardHolders < ActiveRecord::Migration[5.1]
def change
create_table :card_holders do |t|
t.integer :card_id
t.datetime :last_entrance
# put in whatever other columns you need
t.timestamps
end
end
end
使用它非常简单:
> p = Person.create(name: "Sven Reuter")
# directly add a card holder
> p.card_holders << CardHolder.create(card_id: 1, last_entrance: Time.current)
# build a role instead
> p.roles.build(rollable: CardHolder.new(card_id: 2, last_entrance: Time.current)
# get all of the roles
> p.roles
答案 1 :(得分:0)
我会使用Person
表和PersonAttributes
表,该表是该人可能具有的所有属性的并集。如果适用,PersonAttributes
可能会使用STI,例如LoginUser
存储登录和CardHolder
引用Card
s。
清洁简单。