accepts_nested_attributes и validates_uniqueness_of - PullRequest
1 голос
/ 14 октября 2010

Основная проблема: Как объединить коллекции атрибутов по ключу во время массового присвоения из вложенной формы.

Подробности: Я использую следующие модели:

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

Таким образом, существует ограничение на наличие только одного типа контейнера на местоположение. Следующие представления отображают местоположение и связанные контейнеры:

админ / контейнеры / _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 -%>

админ / контейнеры / _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 -%>

модуль 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 - на самом деле я хотел уменьшить - а не увеличить - код и сложность, используя это.

...