Question

J'ai eu du mal à créer un formulaire pour un modèle MongoId qui a un champ tableau. Je veux que ma forme d'avoir sur zone de texte par entrée dans le tableau. Si je crée un nouveau record, la valeur par défaut sera un champ vide (et certains javascript pour ajouter de nouveaux champs dynamiquement sur la page).

J'ai recherché autour d'une solution en utilisant fields_for mais il semble que plus est destiné à traiter le cas où vous avez un tableau d'objets / modèles et non pas le cas, j'ai, ce qui est un tableau de chaînes.

Je vais utiliser l'exemple d'une personne et un numéro de téléphone.

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

Pour le contrôleur, supposons que le contrôleur typique, mais dans la méthode new j'initialisé le tableau de phone_number avec une chaîne vide.

Voici le code de formulaire:

  <%= 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 %>

Cela fonctionne tout va bien. Il y a quelques petites choses que je n'aime pas.

  • Le nom hardcoded du champ dans l'appel text_field_tag.
  • Utilisation text_field_tag ??au lieu de f.text_field
  • Avoir le sentiment que je devrais en quelque sorte utiliserai fields_for au lieu de cela

Quelqu'un at-il de meilleures suggestions sur la façon de mettre en œuvre ce? Ou vous considérez-ce pas?

Était-ce utile?

La solution

Je suis d'accord avec vos préoccupations -

  1. Le nom codé en dur du champ dans l'appel de text_field_tag.

  2. Utilisation text_field_tag ??au lieu de f.text_field

  3. à l'aide fields_for

Après avoir fait quelques recherches ont montré que deux premières préoccupations peuvent être résolus et probablement aussi tiers peuvent mais n'ont pas encore essayé.

 <%= 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%>

Une autre approche propre pourrait être d'avoir générateur de formulaire défini text_field et ayant -

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 %>

Vous pouvez trouver plus d'informations ici

Autres conseils

Vous pouvez travailler avec 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

Et puis, au sein de votre vue, vous pouvez utiliser:

<%= 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 %>

Selon un commentaire publié Mosch dans un commentaire à sa propre solution:

chaque fois que vous utilisez fields_for, il attend un objet avec accesseurs pour les attributs et d'autres méthodes comme new_record? Fondamentalement parlant, le chapeau d'objet pour implémenter l'interface ActiveModel.

La réponse à ma question est qu'il n'y a pas une meilleure façon, à moins que je crée un autre modèle pour le téléphone nubmers, comme cela a été suggéré Mosch.

La deuxième div doit être comme suit

<div class="field"><%= f.fields_for :phone_numbers do | phone | %>
 <%= phone.text_field "phone_numer[]" %><% end %></div>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top