【问题标题】:Adding additional fields on top of an inherited model and expose all super and child class fields在继承模型之上添加附加字段并公开所有超类和子类字段
【发布时间】:2017-09-12 00:08:16
【问题描述】:

我的目标:

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

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 表以添加额外的字段。

如果用户类型是Barber,我希望能够引用user.profile.bio。但是bio 不是基本配置文件的一部分。所以在这种情况下,我必须创建一个关联的Profile and 和关联的BarberProfile 来获得我需要的一切。我可以只做user.profile.first_nameuser.barber_profile.bio,但感觉很乱,而且我正在从本质上相同类型的模型中进行两种不同的关联。我觉得让BarberProfileProfile 继承所有字段并在顶部添加自己特定的Barber 字段应该是一件简单的事情。

如何在 Rails 中做到这一点?

编辑:我想这样做的主要原因之一是我可以在同一表单中为Barber 更新first_namebio 之类的内容。同样,first_namehair_type 在同一表单中用于 Client

【问题讨论】:

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


    【解决方案1】:

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

    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
    

    然后,当您执行“@barber.bio”时,它应该在内部调用“@barber.barber_profile.barber_profile_data.bio”。

    【讨论】:

    • 感谢您的意见。我喜欢这个想法,因为扩展配置文件是我的第一直觉,而且看起来很直观。所以在你的建议中, barber_profile_data 作为一个单独的表存在?是否可以使用此设置从一个表单更新简历?
    • 是的,BarberProfileData 应该有自己的表。关于更新,应该可以检查 rails form_for 方法 fields_for 并使用它。无论如何,您始终可以自定义更新操作,并根据需要设置正确的 fields_for。
    【解决方案2】:

    这听起来像是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 :user
    end
    
    class Client < ApplicationRecord
      acts_as :user
    end
    

    请注意,BarberClient 不应是真正的子类。 ActiveRecord::ActsAs 改为委托给“可操作”类。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-31
      • 2020-11-04
      • 2018-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-13
      • 1970-01-01
      相关资源
      最近更新 更多