it-swarm.com.de

Rails: Felder_für mit Index?

Gibt es eine Methode (oder eine Möglichkeit, eine ähnliche Funktionalität zu erstellen), um einen fields_for_with_index auszuführen?

Beispiel: 

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

Dieses teilweise gerenderte Bild muss wissen, was der aktuelle Index in der fields_for-Schleife ist.

86
Shpigford

Dies wäre tatsächlich ein besserer Ansatz, wenn Sie die Dokumentation von Rails genauer befolgen:

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

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

Es ist auch möglich, das .__ anzugeben. zu verwendende Instanz:

  <%= 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 %>
85
Marco Lazzeri

Die Antwort ist ziemlich einfach, da die Lösung in Rails bereitgestellt wird. Sie können f.options-Parameter verwenden. Also in Ihrem gerenderten _some_form.html.erb

Index kann erreicht werden durch:

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

Sie müssen nichts anderes tun.


Update: Es scheint, dass meine Antwort nicht klar genug war ...

Ursprüngliche HTML-Datei:

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

Gerendertes Unterformular:

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

Ab Rails 4.0.2 ist jetzt ein Index im FormBuilder-Objekt enthalten:

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

Zum Beispiel:

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

Für Schienen 4+

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

Monkey Patch für Rails 3 Support

Damit f.index in Rails 3 funktioniert, müssen Sie den Initialisierungsprogrammen Ihres Projekts einen Affen-Patch hinzufügen, um diese Funktionalität zu fields_for hinzuzufügen

# 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
12
Weston Ganger

Checkout Rendern einer Sammlung von Partials . Wenn Sie davon ausgehen, dass eine Vorlage ein Array durchlaufen muss und für jedes Element eine Untervorlage gerendert werden muss.

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

Dadurch wird „_children.erb“ gerendert und die lokale Variable 'children' an die Vorlage zur Anzeige übergeben. Der Vorlage wird automatisch ein Iterationszähler mit dem Namen der Form partial_name_counter zur Verfügung gestellt. Im obigen Beispiel würde die Vorlage children_counter zugeführt. 

Hoffe das hilft.

7
Syed Aslam

Ich sehe keinen vernünftigen Weg, dies durch die von Rails zur Verfügung gestellten Möglichkeiten zu erreichen, zumindest nicht in -v3.2.14

@Sheharyar Naseer verweist auf den Options-Hash, der zur Lösung des Problems verwendet werden kann, jedoch nicht so weit ich es in der Art und Weise sehen kann, wie er scheint.

Ich habe das gemacht =>

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

oder

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

In meinem Fall gibt g.object_name eine Zeichenfolge wie folgt aus "gallery_set[blog_posts_attributes][2]" für das dritte gerenderte Feld zurück, sodass ich nur den Index in dieser Zeichenfolge finde und ihn verwende.


Eigentlich ist es eine coolere (und vielleicht sauberere) Möglichkeit, ein Lambda zu übergeben und es inkrementell aufzurufen.

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

Und das im Blick

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

Ich weiß, dass dies ein bisschen spät ist, aber vor kurzem musste ich das tun, um den Index der Felder zu erhalten 

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

Ich hoffe, dass das hilft :) 

1
MZaragoza

Wenn Sie die Indizes steuern möchten, überprüfen Sie die 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 =>

Das wird produzieren

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

Wenn das Formular gesendet wird, enthalten die Parameter etwas

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

Ich musste die Index-Option verwenden, um meine Multi-Dropdowns zum Laufen zu bringen. Viel Glück.

0
Cruz Nunez