我正在构建一个系统,其中一些表中的记录是模板记录,可以由所有账户查看,并且稍后可以复制以创建单个账户的实时记录。
这种设计决策背后的原因是模板记录和实时记录共享95%以上相同的代码,因此我不想创建一个单独的表来跟踪大部分相同的字段。
例如,我有一个名为
- id:整数 - account_id:整数 - name:字符串(必需) - is_a_template:布尔值(默认值:false) - is_in_template_library:布尔值(默认值:false)
在这张表中,我有一些模板记录。当我要创建新的实时记录时,我可以使用模板记录。
正如您所看到的,
令人沮丧的是,还有5个以上的其它表是
因此,我非常不愿意走多个表格的路线。
如果我保留单个表并使用多个模型,则最终在表格中会出现不同版本的数据,但这并不是世界末日。 我只通过我的应用程序(或我控制的未来API)与数据进行交互。
我正在考虑的另一个解决方案是向表中添加一个
我的设想是:
这似乎解决了一些问题,让我只使用一个表格和一个模型,但在模型中开始出现有条件的逻辑,这对我来说似乎是一个不好的想法。
是否有更简洁的方法在表格中实现模板系统?
这种设计决策背后的原因是模板记录和实时记录共享95%以上相同的代码,因此我不想创建一个单独的表来跟踪大部分相同的字段。
例如,我有一个名为
workflows
的表:- id:整数 - account_id:整数 - name:字符串(必需) - is_a_template:布尔值(默认值:false) - is_in_template_library:布尔值(默认值:false)
在这张表中,我有一些模板记录。当我要创建新的实时记录时,我可以使用模板记录。
# workflows_controller.rb (pseudo-code, not fully tested)
def create
@workflow_template = Workflow.where(is_a_template: true).find_by(id: params[:workflow_template_id])
@workflow = current_account.workflows.new(workflow_params.merge(@workflow_template.dup))
if @workflow.save
...
else
...
end
end
随着我构建更多的功能,我发现我真的需要两个在表格上运作方式不同的模型。虽然还有几个区别,但以下列出的足以显示它们之间的差异:
class Workflow < ApplicationRecord
default_scope -> { where(is_a_template: false) }
belongs_to :account
validates :account, presence: true
validates :name, presence: true
end
class WorkflowTemplate < ApplicationRecord
default_scope -> { where(is_a_template: true) }
validates :name, presence: true
end
class WorkflowLibraryTemplate < ApplicationRecord
default_scope -> { where(is_a_template: true, is_in_template_library: true) }
validates :name, presence: true
end
正如您所看到的,
workflows
表有三种不同类型的记录:
- 属于账户的“实时”工作流程
- 模板工作流,也属于一个帐户,并被复制以创建“实时”工作流程
- 库模板工作流,不属于任何帐户,可以被任何帐户查看,所以他们可以将其复制到自己的模板列表中
令人沮丧的是,还有5个以上的其它表是
workflows
表的“子”关联。所以,如果我决定需要为每个表格单独的表,那么我最终会从6张表变成18张表,并且每次我添加一个字段时,我都必须针对3个版本进行操作。因此,我非常不愿意走多个表格的路线。
如果我保留单个表并使用多个模型,则最终在表格中会出现不同版本的数据,但这并不是世界末日。 我只通过我的应用程序(或我控制的未来API)与数据进行交互。
我正在考虑的另一个解决方案是向表中添加一个
role:string
字段,这个字段的操作方式非常类似于Rails中的type
字段。 但是,我不想使用STI,因为Rails中有太多内置要求会和我的需求冲突。我的设想是:
class Workflow < ApplicationRecord
scope :templates, -> { where(role: "template") }
scope :library_templates, -> { where(role: "library_template") }
validates :account, presence: true, if: :account_required?
validates :name, presence: true
# If record.role matches one of these, account is required
def account_required
["live", "template"].include?(role.to_s.downcase)
end
end
这似乎解决了一些问题,让我只使用一个表格和一个模型,但在模型中开始出现有条件的逻辑,这对我来说似乎是一个不好的想法。
是否有更简洁的方法在表格中实现模板系统?