在嵌套表单的父参数上使用子模型访问器 (STI)

Using submodel accessor (STI) on parent params for nested forms

我有以下型号:

class Order < ApplicationRecord
class Bill < Order
class Preorder < Order

class Detail < ApplicationRecord
class Metric < Detail
class Unit < Detail

模型 Order 接受 Detail 的嵌套属性,Order 可以是 BillPreorderDetail 可以由 UnitMetric

我正在使用 jsonb_accessor gem 为 UnitMetric

创建附加属性
class Metric < Detail
    jsonb_accessor :data,
      height: :decimal,
      width: :decimal
end

class Unit < Detail
    jsonb_accessor :data,
      quantity: :decimal
end

在我看来,我正在使用 Cocoon gem 为 UnitMetric

生成字段
<%= link_to_add_association(I18n.t('activerecord.models.metric.add'), f, :details, data: {association_insertion_node: '#details', association_insertion_method: :append}, :class => "btn btn-success", 
wrap_object: Proc.new { |detail| detail.type = "Metric"; detail = Metric.new }) %>
<%= link_to_add_association(I18n.t('activerecord.models.unit.add'), f, :details, data: {association_insertion_node: '#details', association_insertion_method: :append}, :class => "btn btn-success",
wrap_object: Proc.new { |detail| detail.type = "Unit"; detail = Unit.new }) %>

在我的控制器中,我有这个方法来验证参数

def order_params(type)
  if type=="Bill"
    params.require(:bill).permit(:client_id, :type, :delivered, :paid, :total_paid, details_attributes: [:id, :total_price, :type, :data, :service_id, :_destroy])
  elsif type=="Preorder"
    params.require(:preorder).permit(:client_id, :type, :delivered, details_attributes: [:id, :total_price, :type, :data, :service_id, :_destroy])
  end
end

表单几乎完美地工作,它存储了我在表单中输入的所有数据,除了 :width, :height, :quantity,当我将它们放入参数时,它给出了一个错误,指出这些参数不属于细节模型并且当我改用 :data 时,该列仍然是空的。

我正在考虑,直接为父模型使用列 Detail 而不是使用 jsonb_accessor,或者为每个 MetricUnit 模型单独使用视图和控制器但是我保留这些解决方案作为最后的手段,因为我想保留代码 Dryier 并尽可能使用更少的列

恕我直言,问题是您正在使用关联 details,这意味着 rails 正在尝试 create/save 一个 Detail。相反,您必须使用 unitsmetrics 的相应关联,以便 rails 知道创建具有相应 jsonb_accessors 的正确对象才能正确保存。

您可以在模型中添加关联:

has_many :metrics 
has_many :units 

我知道这在您的 UI 中可能不那么干净(如果一切都是细节,您可以 add/list 将它们放在一起)。另一种选择是在 Detail 模型中定义所有可能的 json-fields(但不完全确定这是否违背了首先使用它们的目的)。