双嵌套关联 w/Cocoon 和多态性被拒绝

Double nested association w/ Cocoon and Polymorphism gets rejected

所以,我有一个模型 Label 是多态的,另一个模型 Stuff 不是。一个 stuff 可以有很多 labels (也可以称为组),并且 each 和它们中的每一个也可以有一个标签。我正在使用 Cocoon gem 尝试将这些资源添加到单个 edit/new 表单(Stuff 表单)。问题是当我尝试用一​​个新组(其中有新标签)更新 stuff 时,它说这个 Labels labels labelable must exist。我认为这是一个错误,因为第一个标签(组)还没有保存到数据库中,所以它不能给他的嵌套标签一个 id。 (虽然不确定)

此外,这是最好的方法吗?我的意思是,我将标签设为多态只是因为我只需要保存一个字符串,这是不切实际的,而且它会白白占用数据库存储...

废话少说,这是我的代码:

<div class="form-group">
  <label>Groups:</label>
  <div id="group" class="col-md-12 p-0 pl-md-3">
    <%= form.fields_for :labels do |groupForm| %>
      <%= render 'group_fields', f: groupForm %>
      <% end %>
      <div class="text-center">
        <%= link_to_add_association 'Add Group', form, :labels, partial: 'group_fields', class: 'btn btn-success',
            wrap_object: Proc.new { |group| group.labels.build; group } %>
      </div>
  </div>
</div>

我的 _form.html.erb

<div class="nested-fields">
  <div class="field form-group row">
    <%= f.label :name, class: 'col-sm-1 col-form-label' %>
    <div class="col-sm-10">
      <%= f.text_field :name, class: 'form-control ml-2' %>
    </div>
    <div class="col-sm-1 p-0">
      <%= link_to_remove_association "&times;".html_safe, f, class: 'badge badge-pill badge-danger mt-2' %>
    </div>
    <div class="col-12">
      <div id="label" class="col-md-12 p-0 pl-md-5 pt-2">
        <%= f.fields_for :labels do |labelForm| %>
          <%= render 'label_fields', f: labelForm %>
        <% end %>
        <div class="text-center">
          <%= link_to_add_association 'Add Label', f, :labels, class: 'btn btn-success' %>
        </div>
      </div>
    </div>
  </div>
</div>

那是在 _group_fields.html.erb

<div class="nested-fields">
  <div class="field form-group row mb-2">
    <%= f.label :name, class: 'col-sm-1 col-form-label' %>
    <div class="col-sm-10">
      <%= f.text_field :name, class: 'form-control ml-2' %>
    </div>
    <div class="col-sm-1 p-0">
      <%= link_to_remove_association "&times;".html_safe, f, class: 'badge badge-pill badge-danger mt-2' %>
    </div>
  </div>
</div>

这是我的 _label_fields.html.erb

class Label < ApplicationRecord
  belongs_to :labelable, polymorphic: true
  has_many :labels, as: :labelable, dependent: :destroy

  accepts_nested_attributes_for :labels, allow_destroy: true, reject_if: proc { |att| att[:name].blank? }
end

这是我的标签模型

class Stuff< ApplicationRecord
  has_many :labels, as: :labelable, dependent: :destroy

  accepts_nested_attributes_for :labels, allow_destroy: true, reject_if: proc { |att| att[:name].blank? }
end

这是我的 Stuff 模型

我忘了说,如果我只添加标签(组)的第一个 "layer" 而没有在标签上写任何东西(第二个 "layer")并提交表格(我可以这样做它也会更新数据库)当我回来编辑时,我实际上可以毫无问题地修改第二个"layer"。

belongs_to 关系默认为 "required"。这意味着它必须在保存时填写。但是,当保存一个带有嵌套子项的项目时,还不知道 id,而且很明显,rails 无法知道将它们保存在一起时将设置 belongs-to 关联。

有两种处理方法:

  • 使 belongs_to 可选,这将跳过验证,并且保存将起作用。像 belongs_to :labelable, polymorphic: true, optional: true
  • 更好,声明inverse_of,这样rails在保存labels时就知道它对应于labelable关系。

像这样:

has_many :labels, as: :labelable, dependent: :destroy, inverse_of: :labelable 

您可以在任何关联上声明 inverse_of,在 belongs_to 上也是如此,但在大多数情况下,只需在 has_many 上声明它就足够了。在您的特定情况下可能还不够。