Формы для создания и обновления полей массива Mongoid - PullRequest
13 голосов
/ 14 июня 2011

Я изо всех сил пытался создать форму для модели Mongoid с полем массива.Я хочу, чтобы моя форма была в текстовом поле для каждой записи в массиве.Если я создаю новую запись, по умолчанию будет одно пустое поле (и некоторый javascript для динамического добавления новых полей на странице).

Я искал решение с использованием fields_for, но кажется, чтобольше предназначен для случая, когда у вас есть массив объектов / моделей, а не тот случай, который у меня есть, который представляет собой массив строк.

Я собираюсь использовать пример человека и номер телефона.

class Person
  include Mongoid::Document
  field :name, :type => String
  field :phone_numbers, :type => Array
end

Для контроллера просто предположим типичный контроллер, но в методе new я инициализировал массив phone_number одной пустой строкой.

Вот код формы:

  <%= form_for(@person) do |f| %>
    <div class="field">
      <%= f.label :name %><br />
      <%= f.text_field :name %>
    </div>
    <div class="field">
      <%= f.label :phone_numbers %><br />
      <% @person.phone_numbers.each do |phone_number| %>
        <%= text_field_tag "person[phone_numbers][]", phone_number %>
      <% end %>
    </div>
  <% end %>

Это все отлично работает.Есть несколько вещей, которые мне не нравятся.

  • Жестко заданное имя поля в вызове text_field_tag.
  • Использование text_field_tag ​​вместо f.text_field
  • Имея ощущение, будто я должен каким-то образом использовать fields_forиз этого

Кто-нибудь есть какие-либо лучшие предложения о том, как это реализовать?Или вы считаете это правильным?

Ответы [ 4 ]

8 голосов
/ 19 января 2012

Я согласен с вашими проблемами -

  1. Жестко закодированное имя поля в вызове text_field_tag.

  2. Использование text_field_tagвместо f.text_field

  3. с использованием fields_for

После некоторых исследований выяснилось, что первые две проблемы могут быть решены, а, возможно, и третья -но еще не пробовал.

 <%= form_for(@person) do |f| %>
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :phone_numbers %><br />
    <% @person.phone_numbers.each do |phone_number| %>
      <%= f.text_field :phone_numbers, :name => "#{f.object_name}[phone_numbers][]"%>
    <% end %>
  </div>
<%end%>

Другой простой подход мог бы иметь определение text_field, определенное конструктором форм, а затем - - 1023 *

def text_field(attribute, *args)
  args.last.merge!(:name => "#{object_name}[#{attribute}][]") if args.last && args.last.is_a?(Hash) && args.last.delete(:array)
  super(attribute, args)
end

<% @person.phone_numbers.each do |phone_number| %>
  <%= f.text_field :phone_numbers, :array => true%>
<% end %>

Вы можете найти больше информации здесь

3 голосов
/ 14 июня 2011

Вы можете работать с embeds_many:

class Person
  include Mongoid::Document
  field :name
  embeds_many :phone_numbers
end

class PhoneNumber
  include Mongoid::Document
  field :number
  embedded_in :person
end

И тогда, по вашему мнению, вы можете использовать:

<%= form_for(@person) do |f| %>
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <%= @person.phone_numbers.each do |phone_number| %>
    <%= f.fields_for phone_number do |p| %>
      <div class="field">
        <%= p.label :number %><br />
        <%= p.text_field :number %>
      </div>
    <% end %>
  <% end %>
<% end %>
1 голос
/ 17 июня 2011

Согласно комментарию, опубликованному Mosch в комментарии к собственному решению:

всякий раз, когда вы используете fields_for, он ожидает объект с аксессорами для атрибутов и некоторые другие методы, такие как new_record? В сущности, объект предназначен для реализации интерфейса ActiveModel.

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

0 голосов
/ 28 ноября 2012

Второй div должен быть похож на следующий

<div class="field"><%= f.fields_for :phone_numbers do | phone | %>
 <%= phone.text_field "phone_numer[]" %><% end %></div>
...