109 votes

Rails : fields_for avec index ?

Existe-t-il une méthode (ou un moyen d'obtenir une fonctionnalité similaire) 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 %>

Le partiel en cours de rendu doit savoir quel est l'indice actuel dans le fichier fields_for boucle.

3 votes

J'en ai + un dans les rails de base... Je continue à trouver un cas pour celui-ci aussi.

164voto

Sheharyar Points 2063

La réponse est assez simple puisque la solution est fournie par Rails. Vous pouvez utiliser f.options params. Ainsi, dans votre rendu _some_form.html.erb ,

L'index est accessible par :

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

Vous n'avez pas besoin de faire autre chose.


Mise à jour : Il semble que ma réponse n'était pas assez claire...

Fichier HTML original :

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

Sous-forme rendue :

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

11 votes

Cela ne fonctionne pas ici. pouvez-vous fournir le lien de documentation des rails ?

2 votes

@LucasRenan & @graphmeter - Veuillez relire la question, vous devez appeler <%= f.options[:child_index] %> dans votre sous-formulaire rendu (dans ce cas : _some_form.html.erb), et non pas dans l'original builder . Réponse mise à jour pour plus de clarté.

1 votes

Bizarre, j'ai nil pour cela

116voto

Ben Points 151

Depuis Rails 4.0.2, un index est désormais inclus dans l'objet FormBuilder :

https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for

Par exemple :

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

2 votes

Cette méthode fonctionne et est moins lourde à écrire que project_fields.options[:child_index] . Je préfère donc cette solution !

94voto

Marco Lazzeri Points 1191

La réponse ci-dessous a été postée il y a plusieurs années, pour une approche moderne, voir : https://stackoverflow.com/a/22640703/105403


Il s'agit en fait d'une meilleure approche, qui suit de plus près la documentation 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

Il est également possible de spécifier l'instance instance à 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 %>

2 votes

J'aurais aimé qu'il y ait quelque chose d'intégré dans fields_for pour cela, mais comme ce n'est pas le cas, votre réponse a sauvé ma journée. Merci.

1 votes

Vous pouvez également utiliser l'option non documentée :child_index sur fields_for, si vous avez besoin de plus de contrôle sur l'index qui sera rendu, comme ceci : fields_for(:projects, project, child_index : index)

0 votes

Voici le lien API Rails qui fonctionne api.rubyonrails.org/classes/ActionView/Helpers/

7voto

Syed Aslam Points 5549

Checkout Rendu d'une collection de partiels . Si votre exigence est qu'un modèle doit itérer sur un tableau et rendre un sous-modèle pour chacun des éléments.

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

Cela rendra "_children.erb" et passera la variable locale 'children' au modèle pour l'affichage. Un compteur d'itération sera automatiquement mis à 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 alimenté par children_counter .

J'espère que cela vous aidera.

0 votes

J'obtiens "undefined local variable or method 'question_comment_form_counter'" en faisant cela. question_comment_form étant mon nom partiel...

0 votes

Est-ce que la question has_many :comments et comment construisez-vous les commentaires par exemple dans votre nouvelle action ou action d'édition des questions essayez de faire 1.times { question.comments.build }.

5voto

Nultyi Points 414

Je ne vois pas de moyen décent de le faire par les moyens fournis par Rails, du moins pas dans -v3.2.14

@Sheharyar Naseer fait référence aux options de hachage qui peuvent être utilisées pour résoudre le problème mais pas, pour autant que je puisse le voir, de la manière dont il semble le suggérer.

J'ai fait ça =>

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

Dans mon cas g.object_name retourne une chaîne de caractères comme ceci "gallery_set[blog_posts_attributes][2]" pour le troisième champ rendu, donc je fais juste correspondre l'index dans cette chaîne et je l'utilise.


En fait, une façon plus cool (et peut-être plus propre ?) de le faire est de passer une lambda et de l'appeler pour incrémenter.

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

Et le 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 %>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X