Rails : fields_for 색인 포함?


102

할 방법 (또는 유사한 기능을 끌어내는 방법)이 fields_for_with_index있습니까?

예:

<% f.fields_for_with_index :questions do |builder, index| %>  
  <%= render 'some_form', :f => builder, :i => index %>
<% end %>

렌더링되는 부분은 현재 인덱스가 fields_for루프 에 있는지 알아야 합니다.


3
코어 레일에 이것 하나를 추가하고 ...이 사건에 대한 케이스도 계속 찾아 와요.
Nathan Bertram

답변:


92

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

출처 : 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 %>

2
나는 이것을 위해 fields_for에 무언가가 내장되어 있었으면 좋겠지 만, 당신의 대답이 내 하루를 저장하지 않았기 때문에. 감사.
Anders Kindberg

1
또한 문서화되지 않은 옵션을 사용할 수 있습니다 : CHILD_INDEX를 fields_for에, 당신이 더 많은 인덱스는 다음과 같이 렌더링되는 제어 할 필요가있는 경우 : fields_for (: 프로젝트, 프로젝트, CHILD_INDEX : 인덱스)
앤더스 Kindberg을

이것은 작동하는 Rails API 링크입니다. api.rubyonrails.org/classes/ActionView/Helpers/…
Archonic

7
Rails 4.0.2+ 사용자는 색인이 빌더에 빌드되었으므로 Ben의 답변을 확인해야합니다.
notapatch

1
@Marco 당신은 왕 각하입니다. 당신은 내 하루를 구했습니다. :-) 내가 당신에게 10+를 줄 수 있으면 좋겠다 ......!

157

솔루션이 Rails 내에서 제공되므로 대답은 매우 간단합니다. f.options매개 변수 를 사용할 수 있습니다 . 따라서 렌더링 된 _some_form.html.erb,

인덱스는 다음을 통해 액세스 할 수 있습니다.

<%= f.options[:child_index] %>

다른 작업은 필요하지 않습니다.


업데이트 : 내 대답이 명확하지 않은 것 같습니다 ...

원본 HTML 파일 :

<!-- Main ERB File -->
<% f.fields_for :questions do |builder| %>  
  <%= render 'some_form', :f => builder %>
<% end %>

렌더링 된 하위 양식 :

<!-- _some_form.html.erb -->
<%= f.options[:child_index] %>

10
여기서는 작동하지 않습니다. Rails 문서 링크를 제공 할 수 있습니까?
Lucas Renan 2013 년

2
@LucasRenan & @graphmeter-질문을 다시 읽으십시오 . <%= f.options[:child_index] %>원본이 아닌 렌더링 된 하위 양식 (이 경우 : _some_form.html.erb) 을 호출해야합니다 builder. 자세한 설명을 위해 답변이 업데이트되었습니다.
Sheharyar 2013

1
홀수, 내가 얻을 nil그것을 위해
bcackerman

1
@Sheharyar 이것은 Rails 4에서 작동합니다. 그러나 이것은 '1450681048049,1450681050158,1450681056830,1450681141951,1450681219262'와 같은 값을 제공합니다. 하지만 '1,2,3,4,5'형식의 인덱스가 필요합니다. 어떻게해야합니까?
vidal

2
훌륭한. 이것은 절대적으로 받아 들여지는 대답이어야합니다.
jeffdill2

100

Rails 4.0.2부터 색인이 FormBuilder 객체에 포함되었습니다.

https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for

예를 들면 :

<%= form_for @person do |person_form| %>
  ...
  <%= person_form.fields_for :projects do |project_fields| %>
    Project #<%= project_fields.index %>
  ...
  <% end %>
  ...
<% end %>

이것은 작동하고 작성하는 것보다 적습니다 project_fields.options[:child_index]. 그래서 이쪽이 더 좋아요!
Casey

17

Rails 4+ 용

<%= form_for @person do |person_form| %>
  <%= person_form.fields_for :projects do |project_fields| %>
    <%= project_fields.index %>
  <% end %>
<% end %>

Rails 3 지원을위한 Monkey Patch

f.indexRails 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

지금까지 더 나은 대답 .index은 사용 이 훨씬 깨끗합니다.
Lucas Andrade

7

Checkout 부분 컬렉션 렌더링 . 템플릿이 배열을 반복하고 각 요소에 대한 하위 템플릿을 렌더링해야하는 것이 요구 사항 인 경우.

<%= f.fields_for @parent.children do |children_form| %>
  <%= render :partial => 'children', :collection => @parent.children, 
      :locals => { :f => children_form } %>
<% end %>

이렇게하면 "_children.erb"가 렌더링되고 표시 할 템플릿에 지역 변수 'children'이 전달됩니다. 반복 카운터는 양식 이름과 함께 템플릿에서 자동으로 사용할 수있게됩니다 partial_name_counter. 위 예제의 경우 템플릿은 공급 children_counter됩니다.

도움이 되었기를 바랍니다.


그렇게 할 때 "정의되지 않은 지역 변수 또는 메서드 'question_comment_form_counter'"가 표시됩니다. question_comment_form내 부분적인 이름 인 ...
Shpigford 2011 년

의견 및 질문의 신규 또는 수정 조치를 예를 들어 설명을 구축하는 방법은 1.times에게 {question.comments.build} 일을 시도 : 질문 has_many를 수행
에드 빈 라덴

5

적어도 -v3.2.14가 아닌 Rails에서 제공하는 방법을 통해 이것을 수행하는 적절한 방법을 볼 수 없습니다.

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

또는

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

제 경우에는 렌더링 된 세 번째 필드에 대해 g.object_name이와 같은 문자열을 반환 "gallery_set[blog_posts_attributes][2]"하므로 해당 문자열의 인덱스를 일치시키고 사용합니다.


실제로 그것을 수행하는 더 멋진 (그리고 아마도 더 깨끗한?) 방법은 람다를 전달하고 그것을 증가하도록 호출하는 것입니다.

# /controller.rb
index = 0
@incrementer = -> { index += 1}

그리고보기에서

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

1

나는 이것이 조금 늦었다는 것을 알고 있지만 최근에 이것을해야했습니다. 이러한 fields_for의 색인을 얻을 수 있습니다.

<% f.fields_for :questions do |builder| %>
  <%= render 'some_form', :f => builder, :i => builder.options[:child_index] %>
<% end %>

도움이 되었기를 바랍니다. :)


1

fields_for child_index에 추가됨 : 0

<%= form_for @person do |person_form| %>
  <%= person_form.fields_for :projects, child_index: 0 do |project_fields| %>
    <%= project_fields.index %>
  <% end %>
<% end %>

이것이 새로운 베스트 답변입니다.
genkilabs

다른 사람이 이것으로 중복 필드를 얻습니까?

0

인덱스를 제어하려면 index옵션을 확인하십시오.

<%= f.fields_for :other_things_attributes, @thing.other_things.build do |ff| %>
  <%= ff.select :days, ['Mon', 'Tues', 'Wed'], index: 2 %>
  <%= ff.hidden_field :special_attribute, 24, index: "boi" %>
<%= end =>

이것은 생산할 것입니다

<select name="thing[other_things_attributes][2][days]" id="thing_other_things_attributes_7_days">
  <option value="Mon">Mon</option>
  <option value="Tues">Tues</option>
  <option value="Wed">Wed</option>
</select>
<input type="hidden" value="24" name="thing[other_things_attributes][boi][special_attribute]" id="thing_other_things_attributes_boi_special_attribute">

양식이 제출되면 params에 다음과 같은 내용이 포함됩니다.

{
  "thing" => {
  "other_things_attributes" => {
    "2" => {
      "days" => "Mon"
    },
    "boi" => {
      "special_attribute" => "24"
    }
  }
}

멀티 드롭 다운이 작동하도록하려면 인덱스 옵션을 사용해야했습니다. 행운을 빕니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.