Question

Y at-il une méthode (ou une façon de retirer des fonctionnalités similaires) pour faire un fields_for_with_index?

Exemple:

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

Cela étant partiel besoins rendus à savoir ce que l'indice actuel est dans la boucle de fields_for.

Était-ce utile?

La solution

Ce serait en fait une approche mieux, après la documentation Rails plus près:

<% @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/ cours / ActionView / Helpers / FormHelper.html # M006456

Il est également possible de spécifier la par exemple à utiliser:

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

Autres conseils

La réponse est assez simple que la solution est fournie dans Rails. Vous pouvez utiliser params f.options. Ainsi, l'intérieur de votre rendu _some_form.html.erb,

Index est accessible par:

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

Vous n'avez pas besoin de faire quoi que ce soit d'autre.


Mise à jour: Il semble que ma réponse n'a pas été assez clair ...

Fichier original HTML:

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

Rendus Sous-formulaire:

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

Rails 4.0.2, un indice est maintenant inclus dans l'objet FormBuilder:

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

Par exemple:

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

Pour Rails 4 +

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

Monkey patch pour Rails 3 Support

Pour f.index au travail dans Rails 3, vous devez ajouter un patch singe à vos projets initialiseurs d'ajouter cette fonctionnalité à 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

rendu une collection de partials. Si votre exigence est que les besoins d'un modèle à itérer sur un tableau et rendent un modèle de sous pour chacun des éléments.

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

Cela rendra « _children.erb » et passer la variable locale « enfants » au modèle d'affichage. Un compteur d'itération sera automatiquement mis à la disposition du modèle avec un nom de la forme partial_name_counter. Dans le cas de l'exemple ci-dessus, le modèle serait children_counter nourri.

Hope this helps.

Je ne peux pas voir une manière décente de le faire à travers les moyens fournis par Rails, au moins pas dans -v3.2.14

@Sheharyar Naseer fait référence aux options de hachage qui peut être utilisé pour résoudre le problème, mais pas aussi loin que je peux voir dans la façon dont il semble suggérer.

Je l'ai fait =>

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

ou

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

Dans mon g.object_name cas retourne une chaîne comme celui-ci "gallery_set[blog_posts_attributes][2]" pour le troisième champ rendu si je l'index correspondre à peu dans cette chaîne et l'utiliser.


En fait, un refroidisseur (et peut-être plus propre?) Façon de le faire est de passer un lambda et l'appeler à l'incrément.

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

Et dans la vue

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

Je sais que cela est un peu en retard mais j'avais récemment ce faire, vous pouvez obtenir l'index de la fields_for comme ceci

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

J'espère que cette aide :)

Si vous voulez avoir un contrôle sur les index vérifier l'option 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 =>

Cela produira

<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 le formulaire est soumis, params comprendront quelque chose comme

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

Je devais utiliser l'option d'index pour obtenir mon travail à multi-menus déroulants. Bonne chance.

Ajouté à 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 %>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top