关于ruby on rails:用于创建和更新Mongoid数组字段的表单

Forms to create and update Mongoid array fields

我一直在努力为具有数组字段的Mongoid模型创建表单。我希望我的表单在数组中每个条目的文本框上都有。如果我要创建新记录,则默认值为一个空字段(以及一些可在页面上动态添加新字段的JavaScript)。

我一直在寻找使用fields_for的解决方案,但似乎更适合处理您拥有对象/模型数组的情况,而不是我拥有字符串数组的情况。

我将以一个人和一个电话号码为例。

1
2
3
4
5
class Person
  include Mongoid::Document
  field :name, :type => String
  field :phone_numbers, :type => Array
end

对于控制器,仅假设是典型的控制器,但是在new方法中,我使用一个空字符串初始化了phone_number数组。

这是表格代码:

1
2
3
4
5
6
7
8
9
10
11
12
  <%= form_for(@person) do |f| %>
   
      <%= f.label :name %><br />
      <%= f.text_field :name %>
   
   
      <%= f.label :phone_numbers %><br />
      <% @person.phone_numbers.each do |phone_number| %>
        <%= text_field_tag"person[phone_numbers][]", phone_number %>
      <% end %>
   
  <% end %>

一切正常。有些事情我不喜欢。

  • text_field_tag调用中字段的硬编码名称。
  • 使用text_field_tag代替f.text_field
  • 感觉像我应该以某种方式使用fields_for代替这个

有人对如何实施此方法有更好的建议吗?还是您认为这是正确的?


我同意您的担忧-

  • text_field_tag调用中字段的硬编码名称。

  • 使用text_field_tag代替f.text_field

  • 使用fields_for

  • 经过一些研究,发现前两个问题可以解决,第三个问题可以解决,但尚未尝试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     <%= form_for(@person) do |f| %>
     
        <%= f.label :name %><br />
        <%= f.text_field :name %>
     
     
        <%= f.label :phone_numbers %><br />
        <% @person.phone_numbers.each do |phone_number| %>
          <%= f.text_field :phone_numbers, :name =>"#{f.object_name}[phone_numbers][]"%>
        <% end %>
     
    <%end%>

    另一种干净的方法是让表单构建器定义text_field,然后使-

    1
    2
    3
    4
    5
    6
    7
    8
    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 %>

    您可以在此处找到更多信息


    您可以使用embeds_many:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Person
      include Mongoid::Document
      field :name
      embeds_many :phone_numbers
    end

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

    然后,在您的视图中,您可以使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <%= form_for(@person) do |f| %>
     
        <%= f.label :name %><br />
        <%= f.text_field :name %>
     
      <%= @person.phone_numbers.each do |phone_number| %>
        <%= f.fields_for phone_number do |p| %>
         
            <%= p.label :number %><br />
            <%= p.text_field :number %>
         
        <% end %>
      <% end %>
    <% end %>


    根据评论,mosch在对自己的解决方案的评论中发表了文章:

    whenever you use fields_for, it expects an object with accessors for the attributes and some other methods like new_record? Basically speaking, the object hat to implement the ActiveModel interface.

    我的问题的答案是,除非像mosch建议的那样为电话数字用户创建另一个模型,否则没有更好的方法。


    第二个div应该类似于以下

    1
    2
    <%= f.fields_for :phone_numbers do | phone | %>
     <%= phone.text_field"phone_numer[]" %><% end %>