Rails: fields_for avec index?
-
27-10-2019 - |
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
.
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 %>