实现模型子类 - 正确的方法

时间:2013-05-18 16:18:38

标签: ruby-on-rails inheritance nested-forms polymorphic-associations single-table-inheritance

我有一个Event模型,我想创建它的两个子类:FixedEventTasksEvent

事件模型具有以下属性:

uid       :string
title     :string
starts_at :datetime
ends_at   :datetime

FixedEvent继承自Event,并且还具有以下属性:

all_day   :boolean

TasksEvent继承自Event并具有以下属性:

task_id   :integer
occurrence :integer

(事件属性是任务说话的一种特殊方式:执行此任务两/三/ x次。出现代表这是任务的发生(例如,这是用户第二次执行任务))

我昨天花了一整天阅读有关单表继承和多态关联的内容,我仍然不能100%确定在Rails中实现这一点的正确方法。

单表继承在我的数据库中留下了很多空值,因为我最终会得到一个表:uid,title,starts_at,ends_at,all_day,task_id,occurence,type。 这种行为是否会使服务器响应变慢,因为rails将为每个事件查询获取更多(空)数据?

另一方面,多态关联看起来更像是在为模型添加一些额外的功能,而不是对它进行子类化。此外,它还在db中创建了更多的表(在本例中为三个):

events:
id, uid, title, starts_at, ends_at,
created_at, updated_at,
event_type_id, event_type_type

(如果出现问题,建议更好地命名类型)

fixed_events:
id
all_day
created_at
updated_at

tasks_events:
id
task_id
occurrence
created_at
updated_at

这种行为是否会使服务器响应变慢,因为每次我想获取所有FixedEvent / TasksEvent属性时rails必须执行多个db连接?

另外,如何使用STI和/或多态关联创建新的ActiveRecord对象? 我为Polymorphic Association尝试了类似的东西:

def new
  @fixed_event = FixedEvent.new
  @fixed_event.build_event

  respond_to :html
end

然后在form_for:

= f.fields_for :event do |event|
  .field
    = event.label :title
    = event.text_field :title
  .field
    = event.label :starts_at
    = event.datetime_select :starts_at
  .field
    = event.label :ends_at
    = event.datetime_select :ends_at
  .field
    = event.label :description
    = event.text_field :description
  .field
    = event.label :uid
    = event.text_field :uid

我必须在FixedEventTasksEvent中添加这两项内容并且有效:

attr_accessible :event_attributes
accepts_nested_attributes_for :event

这是正确的方法,还是STI更好(或任何其他解决方案)?

1 个答案:

答案 0 :(得分:1)

您希望使用STI,因为它很简单,并且比加载关联快得多。加载一堆空值无需担心,性能明智。另一方面,一旦您的事件表包含数万个条目,连接(甚至是急切加载)就更有可能导致性能问题。

如果选择所有列对您来说都是一个问题,您始终只需选择所有列的子集:

FixedEvent.select('foo, bar').all

好像你已经了解STI,所以我不必教你如何在这里做。这很简单,真的只是创建带有“type”列的“events”表,然后是Event类,然后将其子类化。