tag rails form_with form_for form for ruby-on-rails loops fields-for

ruby on rails - rails - Rieles: fields_for con índice?



rails form_with action (8)

A partir de Rails 4.0.2, ahora se incluye un índice en el objeto FormBuilder:

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

Por ejemplo:

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

¿Hay un método (o una forma de obtener una funcionalidad similar) para hacer un fields_for_with_index ?

Ejemplo:

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

Esa fields_for parcial necesita saber cuál es el índice actual en el bucle fields_for .


En realidad, este sería un mejor enfoque, siguiendo más de cerca la documentación de 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 %>

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

También es posible especificar la instancia que se utilizará:

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


La respuesta es bastante simple ya que la solución se proporciona dentro de Rails. Puede usar parametros de f.options . Entonces, dentro de su renderizado _some_form.html.erb ,

El índice se puede acceder por:

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

No necesitas hacer nada más.

Actualización: parece que mi respuesta no fue lo suficientemente clara ...

Archivo HTML original:

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

Renderizado Sub-Formulario:

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


No puedo ver una manera decente de hacerlo a través de los modos proporcionados por Rails, al menos no en -v3.2.14

@Sheharyar Naseer hace referencia al hash de opciones que se puede usar para resolver el problema, pero no tan lejos como puedo ver en la forma en que parece sugerir.

Hice esto =>

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

o

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

En mi caso, g.object_name devuelve una cadena como esta "gallery_set[blog_posts_attributes][2]" para el tercer campo representado, por lo que solo "gallery_set[blog_posts_attributes][2]" con el índice en esa cadena y lo uso.

En realidad, una manera más genial (y ¿quizás más limpia?) De hacerlo es pasar un lambda y llamarlo para incrementarlo.

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

Y el en la vista

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


Pago y envío de una colección de parciales . Si su requisito es que una plantilla necesita iterar sobre una matriz y renderizar una sub plantilla para cada uno de los elementos.

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

Esto generará "_children.erb" y pasará la variable local "children" a la plantilla para mostrar. Un contador de iteración se pondrá automáticamente a disposición de la plantilla con un nombre de la forma partial_name_counter . En el caso del ejemplo anterior, la plantilla se alimentaría con children_counter .

Espero que esto ayude.


Sé que esto es un poco tarde, pero recientemente tuve que hacer esto para obtener el índice de los campos_ para así

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

Espero que esto ayude :)


Si desea tener control sobre los índices, consulte la opción de 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 =>

Esto producirá

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

Si se envía el formulario, los parámetros incluirán algo así como

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

Tuve que usar la opción de índice para hacer que mis múltiples listas desplegables funcionaran. Buena suerte.


Rails 4+ y Rails 3 (con el parche a continuación)

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

Para el soporte de Rails 3

Para que f.index funcione en Rails 3, debe agregar un parche mono a los inicializadores de sus proyectos para agregar esta funcionalidad a 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