在继承的模型上添加其他字段并公开所有超类和子类字段

时间:2017-04-16 03:34:05

标签: ruby-on-rails inheritance database-design associations single-table-inheritance

我的目标:

我尝试使用不同的个人资料创建两种不同类型的用户。

BarberClientBarberProfileClientProfile

我的基础User对象包含emailpassword等信息,以及Devise跟踪的所有其他字段。

我希望基本User模型有一个Profile来跟踪我希望所有用户拥有的所有基本信息。例如,first_namelast_nameavatar

我使用单表继承来创建两种不同类型的用户:ClientBarber

我希望每种类型的用户都有一个与之关联的基础Profile,然后分别拥有属于BarberProfileClientProfile的其他字段。

BarberProfile会有Barber所需的内容,但Client不会。例如,bioClientProfile会有Client所需的内容,但Barber不会。例如,hair_type

我目前拥有什么,以及我的问题:

如上所述,我已为UserProfile创建了一个表格。所以我可以致电user.profile.first_name。我创建了一个BarberProfileClientProfile表,以便添加额外的字段。

如果用户类型为user.profile.bio,我希望能够引用Barber。但bio不是基本资料的一部分。因此,在这种情况下,我必须创建关联的Profile 以及关联的BarberProfile以获取我需要的所有内容。我可以做user.profile.first_nameuser.barber_profile.bio,但感觉很乱,而且我从基本上相同类型的模型中做出两种不同的关联。我觉得让BarberProfile继承Profile中的所有字段并在顶部添加自己的特定Barber字段应该是一件简单的事情。

如何在Rails中执行此操作?

修改:我想要这样做的一个主要原因是,我可以在{{1}的同一表单中更新first_namebio等内容}。同样,Barber的同一表单中的first_namehair_type

2 个答案:

答案 0 :(得分:1)

如果你想避免在Profile和Client / BarberProfile的用户上使用两个关联,我认为你应该使ClientProfile和BarberProfile扩展Profile(单表继承),并且每个"都有一个:barber_profile_data&#34 ; (我不知道怎么称呼它)。要修复长方法调用,可以使用委托方法。

class Barber > User
  has_one :barber_profile
  delegate :bio, to: :barber_profile

class Client < User
  has_one :client_profile
  delegate :first_name, to: :client_profile

class BarberProfile < Profile
  has_one :barber_profile_data
  delegate :bio, to: :barber_profile_data

class ClientProfile < Profile
  has_one :client_profile_data
  delegate :first_name, to: :client_profile_data

然后,当你执行&#34; @ barber.bio&#34;时,它应该在内部调用&#34; @ barber.barber_profile.barber_profile_data.bio&#34;。

答案 1 :(得分:0)

这听起来像是Multiple Table Inheritance的一个很好的用例。在MTI中,您可以使用其他表来装饰基本模型。

MTI的主要优点是clientsbarbers表可以包含该类型与STI的特定列,这要求您按设计将所有内容填入users(这就是为什么他们称之为单桌)。

create_table "barbers", force: :cascade do |t|
  # only the specific attributes
  t.text     "bio"
end

create_table "clients", force: :cascade do |t|
  # only the specific attributes
  t.string   "hair_type"
end

create_table "users", force: :cascade do |t|
  t.string   "email"
  t.string   "first_name"
  t.string   "last_name"
  # ... all the other common attributes
  t.integer  "actable_id"
  t.string   "actable_type"
  t.datetime "created_at",   null: false
  t.datetime "updated_at",   null: false
end

这是ActiveRecord::ActsAs gem的一个例子。

class User < ApplicationRecord
  actable
end

class Barber  < ApplicationRecord
  acts_as :product
end

class Barber  < ApplicationRecord
  acts_as :product
end

请注意,BarberClient不应该是真正的子类。 ActiveRecord::ActsAs代替“actable”类。

然后,您可以Barber.allClient.all获取特定类型,或使用User.all.map(:specific)获取所有类型的装饰用户。