【问题标题】:How to model these object types that can be converted to/from each other, but have different associations如何对这些可以相互转换但具有不同关联的对象类型进行建模
【发布时间】:2012-05-27 22:15:06
【问题描述】:

我目前有两个模型作为 STI。

class Event
class BlockedTime < Event
class Appointment < Event

除了 'Appointment' has_one 'client' 和 has_one 'service' 之外,这些模型是相似的,而 'BlockedTime' 没有这些关联。

此外,我希望能够轻松地在这两种类型之间进行转换,当我搜索时,我通常会同时搜索两种类型,而不是其中一种。出于这些原因,我犹豫将它们分成单独的表格。

对于类型之间的切换,我目前以相同的形式执行此操作,使用父“事件”类型,并将“类型”存储为隐藏字段,但这绝对不是很好。我必须在控制器中进行各种转换以检查验证等。

您建议如何建模?

【问题讨论】:

  • 你真的需要它们是独立的模型吗?似乎几个标志就可以了。
  • 你能扩展一下吗?当某些记录没有关联时,我将如何处理 has_one 关联的情况?
  • 只是大声思考。我从未使用过 STI,所以我可能错了。没关系:)
  • 不确定“在两种类型之间转换”是什么意思。 看起来 STI 是合适的,这样每个模型都有自己的验证和关联,并且底层类包含​​共享属性,这意味着不需要“转换”。
  • 这个问题,例如:如果我编辑一个“BlockedTime”,表单有一个blocked_time对象,提交到blocked_time控制器。但是,如果用户将其更改为表单中的“约会”(通过单选按钮),则 URL 仍指向不起作用的“blocked_time”控制器,因为它会运行错误的验证。

标签: ruby-on-rails ruby-on-rails-3 database-design activerecord model


【解决方案1】:

所以,如果我遇到这个问题,我可能会对数据库进行不同的建模。

我会使用 Composition 模式,而不是 STI/Inheritance 模式。所以:

class Appointment
  belongs_to :block_time, :class_name => "BlockTime"
  ...
end

class BlockTime
   has_one :appointment
   accepts_nested_attributes_for :appointment, :allow_destroy => :true, 
                                               :reject_if => :all_blank

  ...
end

控制器

class AppointmentsController < ApplicationController
  ...

  def new
    @block_time = BlockTime.new
    @block_time.appointment or @block_time.build_appointment
    ...
  end

  def edit
    @block_time = BlockTime.includes(:appointment).find(params[:id])
    @block_time.appointment or @block_time.build_appointment
  end

  ...
end

表格或至少部分表格

<%= f.fields_for :appointment do |g| %>
  <div>
    <%= g.radio_button :_destroy, "1", :checked => !g.object.persisted? %>
    <%= g.label :_destroy_1, "Has no Appointment" %>

    <%= g.radio_button :_destroy, "0", :checked => g.object.persisted? %>
    <%= g.label :_destroy_0, "Has Appointment" %>
  </div>

  <p>
    Client: <%= g.text_field :client %>
  </p>
<% end %>

这部分表单使用persisted? 来检查Appointment 对象是新记录还是已持久化到数据库中。然后,如果它已经存在并且您想将其删除,那么它将为accepts_nested_attributes_for 抛出_destroy 标志并删除现有的appointment 关联以使其成为免费的BlockTime

然后您也可以在此表单中包含所有 Appointment 字段。 您可能想根据radio_button 的选择编写一些 javascript 来禁用/启用字段

【讨论】:

  • 谢谢,但是 BlockTime 由什么组成,只是日期/时间?而且这似乎并没有解决阻塞时间没有客户端、服务关联的关联问题,还是我错过了什么?
  • 所以BlockTime 只存储任何相关的日期/时间信息以及外键appointment_id。然后Appointment 将保存客户端和服务数据。实际上,Appointment 将依赖于 BlockTime,但 BlockTime 也可以是独立记录。
  • 如果 BlockTime 属于_to :appointment,它不能单独存在,是吗?
  • 控制器如何知道类型之间的区别?正如我所提到的,相同的表单用于通过单选按钮在两种类型之间切换。
  • 当然BlockTime 可以独立存在,仅仅因为我们有一个外键并不意味着我们需要使用它。此外,对于控制器,我不知道您的应用程序是如何工作的,因此我无法真正帮助您,但请记住,您不需要 1:1:model-to-controller 比率。如果我有时间,我明天会更新我的答案,以说明我将如何处理控制器。
猜你喜欢
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多