2011-01-31 30 views
78

Có phương pháp nào (hoặc cách để tắt chức năng tương tự) để thực hiện fields_for_with_index không?Đường ray: fields_for có chỉ mục?

Ví dụ:

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

Đó nhu cầu trả lại hạnh phúc một phần để biết chỉ số hiện nay là trong fields_for vòng lặp.

+3

Tôi muốn + một trong những đường ray chính ... Hãy xem xét một trường hợp cho cái này. –

Trả lời

81

Điều này thực sự sẽ là một phương pháp tốt hơn, sau Rails tài liệu chặt chẽ hơn:

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

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

Cũng có thể để xác định các trường hợp sẽ được sử dụng:

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

Tôi ước gì có thứ gì đó được xây dựng trong field_for cho việc này, nhưng vì câu trả lời của bạn không được lưu trong ngày của tôi. Cảm ơn. –

+0

Bạn cũng có thể sử dụng tùy chọn không có giấy tờ: child_index trên fields_for, nếu bạn cần thêm quyền kiểm soát đối với chỉ mục được hiển thị, như sau: fields_for (: projects, project, child_index: index) –

+2

'@ questions.each_with_index' cũng hoạt động – Archonic

7

Thanh toán Rendering a collection of partials. Nếu yêu cầu của bạn là một khuôn mẫu cần lặp qua một mảng và hiển thị một mẫu con cho mỗi phần tử.

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

Điều này sẽ hiển thị “_children.erb“ và chuyển biến cục bộ 'trẻ em' sang mẫu để hiển thị. Một bộ đếm lặp sẽ tự động được cung cấp cho mẫu với tên của biểu mẫu partial_name_counter. Trong trường hợp ví dụ trên, mẫu sẽ được cung cấp children_counter.

Hy vọng điều này sẽ hữu ích.

+0

Tôi nhận được "biến cục bộ không xác định hoặc phương thức 'question_comment_form_counter'" khi thực hiện điều đó. 'question_comment_form' là tên riêng của tôi ... – Shpigford

+0

Đặt câu hỏi has_many: nhận xét và cách bạn xây dựng các nhận xét chẳng hạn trong hành động mới hoặc chỉnh sửa của bạn về các câu hỏi, hãy thử thực hiện 1.times {question.comments.build} –

125

Câu trả lời khá đơn giản vì giải pháp được cung cấp trong Rails. Bạn có thể sử dụng thông số f.options. Vì vậy, bên trong của bạn render _some_form.html.erb,

Index có thể được truy cập bằng cách:

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

Bạn không cần phải làm bất cứ điều gì khác.


Cập nhật: Dường như câu trả lời của tôi là không đủ rõ ràng ...

gốc tập tin HTML:

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

rendered Sub-Form:

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

Bạn cần nhiều phiếu bầu hơn! – Jeff

+8

nó không hoạt động ở đây. bạn có thể cung cấp liên kết tài liệu đường ray không? –

+3

cũng không hoạt động đối với tôi. – graphmeter

6

Tôi không thể thấy một cách phù hợp để thực hiện điều này thông qua các cách được Rails cung cấp, ít nhất là không phải trong v3.2.14

@Sheharyar Naseer tham chiếu đến băm tùy chọn có thể được sử dụng để giải quyết vấn đề nhưng không xa như tôi thấy dường như đề nghị.

Tôi đã làm điều này =>

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

hoặc

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

Trong trường hợp của tôi g.object_name trả về một chuỗi như "gallery_set[blog_posts_attributes][2]" này cho lĩnh vực thứ ba trả lại vì vậy tôi chỉ phù hợp với các chỉ số trong chuỗi đó và sử dụng nó.


Thực ra cách làm mát hơn (và có thể sạch hơn?) Là chuyển một lambda và gọi nó là tăng dần.

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

Và trong giao diện

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

Tính đến Rails 4.0.2, một chỉ số hiện nay bao gồm trong đối tượng FormBuilder:

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

Ví dụ:

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

Điều này hoạt động và ít hơn để viết ra hơn 'project_fields.options [: child_index]'. Vì vậy, tôi thích cách này tốt hơn! – Casey

+0

Tốt hơn nhiều, điều này nên được chấp nhận. Cảm ơn bạn! – gregblass

7

Rails 4+ và Rails 3 (với bản vá bên dưới)

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

Đối với Rails 3 hỗ trợ

Để có được f.index làm việc trong Rails 3 bạn cần phải thêm một bản vá khỉ để initializers dự án của bạn để thêm chức năng này vào 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 
0

Nếu bạn muốn có quyền kiểm soát các chỉ số kiểm tra index tùy chọn

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

này sẽ sản xuất

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

Nếu mẫu được gửi, params sẽ bao gồm một cái gì đó giống như

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

tôi đã phải sử dụng tùy chọn chỉ số để có được đa Dropdowns của tôi làm việc. Chúc may mắn.

1

tôi biết rằng đây là hơi muộn nhưng gần đây tôi phải làm điều này bạn có thể nhận được các chỉ số của fields_for như thế này

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

Tôi hy vọng rằng điều này sẽ giúp :)

Các vấn đề liên quan