Accepts_nested_attributes 和 validates_uniqueness_of

发布于 2024-09-27 19:58:49 字数 2682 浏览 2 评论 0原文

中心问题:在嵌套表单的批量分配过程中,如何通过键合并属性集合。

详细信息:我使用以下模型:

class Location < ActiveRecord::Base
  has_many :containers,
    :dependent => :destroy,
    :order => "container_type ASC"

  validates_associated          :containers
  accepts_nested_attributes_for :containers,
    :allow_destroy => true,
    :reject_if => proc {|attributes| attributes["container_count"].blank? }
end

class Container < ActiveRecord::Base
  belongs_to :location, :touch => true

  validates_presence_of     :container_type
  validates_uniqueness_of   :container_type, :scope => :location_id
  validates_numericality_of :container_count,
    :greater_than => 0,
    :only_integer => true
end

因此存在每个位置只能有一种集装箱类型的限制。以下视图呈现位置和关联的容器:

admin/containers/_index.html.erb

<% remote_form_for [:admin, setup_containers(@location)] do |f| -%>
  <% f.fields_for :containers do |container_form| -%>
    <%= render "admin/containers/form", :object => container_form %>
  <% end -%>
  <%= f.submit "Speichern" %>
<% end -%>

admin/containers/_form.html.erb

<% div_for form.object do -%>
  <span class="label">
    <%- if form.object.new_record? -%>
      <%= form.select :container_type, { "Type1" => 1, "Type2" => 2, ... } %>
    <%- else -%>
      <%= form.label :container_count, "#{form.object.name}-Container" %>
      <%= form.hidden_field :container_type %>
    <%- end -%>
  </span>
  <span class="count"><%= form.text_field :container_count %></span>
  <%- unless form.object.new_record? -%>
    <span class="option"><%= form.check_box :_destroy %> Löschen?</span>
  <%- end -%>
<% end -%>

module Admin::ContainersHelper 本质上

def setup_containers(location)
  return location if location.containers.any? {|l| l.new_record? }
  returning location do |l|
    all_container_types = [1, 2, ...]
    used_container_types = l.containers.try(:collect, &:container_type) || []
    next_container_type = (all_container_types - used_container_types).first
    l.containers.build :container_type => next_container_type if next_container_type
  end
end

,助手将一个新容器添加到集合中,除非所有类型都已关联或集合中已存在新容器。该容器被预初始化为第一个尚未定义的容器类型。到目前为止,效果非常好。添加容器有效。删除容器有效。

问题是:我想实现选择和添加集合中已有的容器类型应该总结它们的计数(相反,它会违反唯一约束)。我不确定在不实现/重新发明完整的 accepts_nested_attributes_for 魔法的情况下最好的方法是什么 - 实际上我想通过使用它来减少 - 而不是增加 - 代码和复杂性。

The central problem: How do you merge attribute collections by a key during mass assignment from a nested form.

The details: I am using the following models:

class Location < ActiveRecord::Base
  has_many :containers,
    :dependent => :destroy,
    :order => "container_type ASC"

  validates_associated          :containers
  accepts_nested_attributes_for :containers,
    :allow_destroy => true,
    :reject_if => proc {|attributes| attributes["container_count"].blank? }
end

class Container < ActiveRecord::Base
  belongs_to :location, :touch => true

  validates_presence_of     :container_type
  validates_uniqueness_of   :container_type, :scope => :location_id
  validates_numericality_of :container_count,
    :greater_than => 0,
    :only_integer => true
end

So there is a constraint of having only one container type per location. The following views render the location and associated containers:

admin/containers/_index.html.erb

<% remote_form_for [:admin, setup_containers(@location)] do |f| -%>
  <% f.fields_for :containers do |container_form| -%>
    <%= render "admin/containers/form", :object => container_form %>
  <% end -%>
  <%= f.submit "Speichern" %>
<% end -%>

admin/containers/_form.html.erb

<% div_for form.object do -%>
  <span class="label">
    <%- if form.object.new_record? -%>
      <%= form.select :container_type, { "Type1" => 1, "Type2" => 2, ... } %>
    <%- else -%>
      <%= form.label :container_count, "#{form.object.name}-Container" %>
      <%= form.hidden_field :container_type %>
    <%- end -%>
  </span>
  <span class="count"><%= form.text_field :container_count %></span>
  <%- unless form.object.new_record? -%>
    <span class="option"><%= form.check_box :_destroy %> Löschen?</span>
  <%- end -%>
<% end -%>

module Admin::ContainersHelper

def setup_containers(location)
  return location if location.containers.any? {|l| l.new_record? }
  returning location do |l|
    all_container_types = [1, 2, ...]
    used_container_types = l.containers.try(:collect, &:container_type) || []
    next_container_type = (all_container_types - used_container_types).first
    l.containers.build :container_type => next_container_type if next_container_type
  end
end

Essentially, the helper adds an new container to the collections except all types have already been associated or there is already a new container in the collection. This container is preinitialized to the first not-yet-defined container type. This works out pretty well so far. Adding containers works. Deleting containers works.

The problem is: I want to achieve that choosing and adding a container type which is already in the collection should sum up their counts (instead it would violate the unique constraint). I'm not sure what would be the best way without implementing/reinventing the complete accepts_nested_attributes_for magic - actually I wanted to reduce - not increase - code and complexity by using that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文