Rails:fields_for带索引?

Shp*_*ord 94 loops ruby-on-rails fields-for

是否有方法(或实现类似功能的方法)来做fields_for_with_index

例:

<% f.fields_for_with_index :questions do |builder, index| %>  
  <%= render 'some_form', :f => builder, :i => index %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

部分呈现需要知道当前索引在fields_for循环中是什么.

She*_*yar 154

答案非常简单,因为Rails中提供了解决方案.你可以使用f.options参数.所以,在你渲染的内部_some_form.html.erb,

索引可以通过以下方式访问

<%= f.options[:child_index] %>
Run Code Online (Sandbox Code Playgroud)

你不需要做任何其他事情.


更新:似乎我的答案不够明确......

原始HTML文件:

<!-- Main ERB File -->
<% f.fields_for :questions do |builder| %>  
  <%= render 'some_form', :f => builder %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

呈现子表格:

<!-- _some_form.html.erb -->
<%= f.options[:child_index] %>
Run Code Online (Sandbox Code Playgroud)

  • 它不在这里工作.你能提供rails文档链接吗? (8认同)
  • @LucasRenan&@graphmeter - 请再次阅读问题,你需要在渲染的子表单中调用`<%= f.options [:child_index]%>`(在本例中为:_some_form.html.erb),而不是int最初的"建造者".更新答案以获得更多说明. (2认同)
  • 杰出的。这绝对应该是公认的答案。 (2认同)

Ben*_*Ben 93

从Rails 4.0.2开始,FormBuilder对象中现在包含一个索引:

http://apidock.com/rails/v4.0.2/ActionView/Helpers/FormHelper/fields_for

例如:

<%= form_for @person do |person_form| %>
  ...
  <%= person_form.fields_for :projects do |project_fields| %>
    Project #<%= project_fields.index %>
  ...
  <% end %>
  ...
<% end %>
Run Code Online (Sandbox Code Playgroud)

  • 这有效并且比`project_fields.options[:child_index]`少写。所以我更喜欢这种方式! (2认同)

Mar*_*eri 86

这实际上是一种更好的方法,更紧密地遵循Rails文档:

<% @questions.each.with_index do |question,index| %>
    <% f.fields_for :questions, question do |fq| %>  
        # here you have both the 'question' object and the current 'index'
    <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

来自:http: //railsapi.com/doc/rails-v3.0.4/classes/ActionView/Helpers/FormHelper.html#M006456

也可以指定要使用的实例:

  <%= form_for @person do |person_form| %>
    ...
    <% @person.projects.each do |project| %>
      <% if project.active? %>
        <%= person_form.fields_for :projects, project do |project_fields| %>
          Name: <%= project_fields.text_field :name %>
        <% end %>
      <% end %>
    <% end %>
  <% end %>
Run Code Online (Sandbox Code Playgroud)

  • Rails 4.0.2+用户应查看Ben的答案,因为索引现已内置到构建器中. (7认同)
  • 我希望field_for内置了一些东西,但是因为没有你的答案在我的日子里得救了.谢谢. (2认同)

Wes*_*ger 15

适用于Rails 4+

<%= form_for @person do |person_form| %>
  <%= person_form.fields_for :projects do |project_fields| %>
    <%= project_fields.index %>
  <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

Monkey Patch For Rails 3支持

f.index在Rails 3中工作,您需要向项目初始化程序添加一个猴子补丁以添加此功能fields_for

# config/initializers/fields_for_index_patch.rb

module ActionView
  module Helpers
    class FormBuilder

      def index
        @options[:index] || @options[:child_index]
      end

      def fields_for(record_name, record_object = nil, fields_options = {}, &block)
        fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
        fields_options[:builder] ||= options[:builder]
        fields_options[:parent_builder] = self
        fields_options[:namespace] = options[:namespace]

        case record_name
          when String, Symbol
            if nested_attributes_association?(record_name)
              return fields_for_with_nested_attributes(record_name, record_object, fields_options, block)
            end
          else
            record_object = record_name.is_a?(Array) ? record_name.last : record_name
            record_name   = ActiveModel::Naming.param_key(record_object)
        end

        index = if options.has_key?(:index)
                  options[:index]
                elsif defined?(@auto_index)
                  self.object_name = @object_name.to_s.sub(/\[\]$/,"")
                  @auto_index
                end

        record_name = index ? "#{object_name}[#{index}][#{record_name}]" : "#{object_name}[#{record_name}]"
        fields_options[:child_index] = index

        @template.fields_for(record_name, record_object, fields_options, &block)
      end

      def fields_for_with_nested_attributes(association_name, association, options, block)
        name = "#{object_name}[#{association_name}_attributes]"
        association = convert_to_model(association)

        if association.respond_to?(:persisted?)
          association = [association] if @object.send(association_name).is_a?(Array)
        elsif !association.respond_to?(:to_ary)
          association = @object.send(association_name)
        end

        if association.respond_to?(:to_ary)
          explicit_child_index = options[:child_index]
          output = ActiveSupport::SafeBuffer.new
          association.each do |child|
            options[:child_index] = nested_child_index(name) unless explicit_child_index
            output << fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block)
          end
          output
        elsif association
          fields_for_nested_model(name, association, options, block)
        end
      end

    end
  end
end
Run Code Online (Sandbox Code Playgroud)


Sye*_*lam 7

结帐渲染部分的集合.如果您的要求是模板需要迭代数组并为每个元素呈现子模板.

<%= f.fields_for @parent.children do |children_form| %>
  <%= render :partial => 'children', :collection => @parent.children, 
      :locals => { :f => children_form } %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

这将呈现"_children.erb"并将局部变量"children"传递给模板以供显示.将使用表单名称自动为模板提供迭代计数器partial_name_counter.在上面的例子的情况下,模板将被馈送children_counter.

希望这可以帮助.


iNu*_*lty 6

我无法通过Rails提供的方式看到这样做的好方法,至少在-v3.2.14中没有

@Sheharyar Naseer引用了可用于解决问题的选项哈希,但并不是我所能看到的方式.

我这样做了=>

<%= f.fields_for :blog_posts, {:index => 0} do |g| %>
  <%= g.label :gallery_sets_id, "Position #{g.options[:index]}" %>
  <%= g.select :gallery_sets_id, @posts.collect  { |p| [p.title, p.id] } %>
  <%# g.options[:index] += 1  %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

要么

<%= f.fields_for :blog_posts do |g| %>
  <%= g.label :gallery_sets_id, "Position #{g.object_name.match(/(\d+)]/)[1]}" %>
  <%= g.select :gallery_sets_id, @posts.collect  { |p| [p.title, p.id] } %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

在我的情况下, 为渲染的第三个字段g.object_name返回一个这样的字符串"gallery_set[blog_posts_attributes][2]",所以我只匹配该字符串中的索引并使用它.


实际上,冷却器(也许更干净?)的方法是传递一个lambda并调用它来递增.

# /controller.rb
index = 0
@incrementer = -> { index += 1}
Run Code Online (Sandbox Code Playgroud)

而在视图中

<%= f.fields_for :blog_posts do |g| %>
  <%= g.label :gallery_sets_id, "Position #{@incrementer.call}" %>
  <%= g.select :gallery_sets_id, @posts.collect  { |p| [p.title, p.id] } %>
<% end %>
Run Code Online (Sandbox Code Playgroud)