Ruby-on-rails Rails:fields_for 带索引?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4853373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails: fields_for with index?
提问by Shpigford
Is there a method (or way to pull off similar functionality) to do a fields_for_with_index?
有没有一种方法(或实现类似功能的方法)来做一个fields_for_with_index?
Example:
例子:
<% f.fields_for_with_index :questions do |builder, index| %>
<%= render 'some_form', :f => builder, :i => index %>
<% end %>
That partial being rendered needs to know what the current index is in the fields_forloop.
正在渲染的部分需要知道fields_for循环中的当前索引是什么。
采纳答案by Marco Lazzeri
This would actually be a better approach, following Rails documentation more closely:
这实际上是一种更好的方法,更密切地遵循 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 %>
From: http://railsapi.com/doc/rails-v3.0.4/classes/ActionView/Helpers/FormHelper.html#M006456
来自:http: //railsapi.com/doc/rails-v3.0.4/classes/ActionView/Helpers/FormHelper.html#M006456
It's also possible to specify the instance to be used:
也可以指定要使用的实例:
<%= 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 %>
回答by Sheharyar
The answer is quite simple as the solution is provided within Rails. You can use f.optionsparams. So, inside your rendered _some_form.html.erb,
答案很简单,因为 Rails 提供了解决方案。您可以使用f.options参数。所以,在你的渲染中_some_form.html.erb,
Index can be accessed by:
可以通过以下方式访问索引:
<%= f.options[:child_index] %>
You don't need to do anything else.
你不需要做任何其他事情。
Update:It seems that my answer wasn't clear enough...
更新:看来我的回答不够清楚......
Original HTML File:
原始 HTML 文件:
<!-- Main ERB File -->
<% f.fields_for :questions do |builder| %>
<%= render 'some_form', :f => builder %>
<% end %>
Rendered Sub-Form:
渲染子表单:
<!-- _some_form.html.erb -->
<%= f.options[:child_index] %>
回答by Ben
As of Rails 4.0.2, an index is now included in the FormBuilder object:
从 Rails 4.0.2 开始,一个索引现在包含在 FormBuilder 对象中:
https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for
https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for
For example:
例如:
<%= form_for @person do |person_form| %>
...
<%= person_form.fields_for :projects do |project_fields| %>
Project #<%= project_fields.index %>
...
<% end %>
...
<% end %>
回答by Weston Ganger
For Rails 4+
对于 Rails 4+
<%= form_for @person do |person_form| %>
<%= person_form.fields_for :projects do |project_fields| %>
<%= project_fields.index %>
<% end %>
<% end %>
Monkey Patch For Rails 3 Support
支持 Rails 3 的 Monkey 补丁
To get f.indexto work in Rails 3 you need to add an monkey patch to your projects initializers to add this functionality to fields_for
要f.index在 Rails 3 中工作,您需要向项目初始值设定项添加一个猴子补丁以将此功能添加到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
回答by Syed Aslam
Checkout Rendering a collection of partials. If your requirement is that a template needs to iterate over an array and render a sub template for each of the elements.
Checkout呈现部分的集合。如果您的要求是模板需要遍历数组并为每个元素呈现子模板。
<%= f.fields_for @parent.children do |children_form| %>
<%= render :partial => 'children', :collection => @parent.children,
:locals => { :f => children_form } %>
<% end %>
This will render “_children.erb“ and pass the local variable 'children' to the template for display. An iteration counter will automatically be made available to the template with a name of the form partial_name_counter. In the case of the example above, the template would be fed children_counter.
这将渲染“_children.erb”并将局部变量“children”传递给模板进行显示。迭代计数器将自动提供给具有表单名称的模板partial_name_counter。在上面的例子中,模板将被馈送children_counter。
Hope this helps.
希望这可以帮助。
回答by iNulty
I can't see a decent way to do this through the ways provided by Rails, at least not in -v3.2.14
我看不到通过 Rails 提供的方式来做到这一点的体面方法,至少在 -v3.2.14 中没有
@Sheharyar Naseer makes reference to the options hash which can be used to solve the problem but not as far as I can see in the way he seems to suggest.
@Sheharyar Naseer 参考了可用于解决问题的选项哈希,但不是我所看到的他似乎建议的方式。
I did this =>
我这样做了 =>
<%= 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 %>
or
或者
<%= 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 my case g.object_namereturns a string like this "gallery_set[blog_posts_attributes][2]"for the third field rendered so I just match the index in that string and use it.
在我的情况下, 为呈现的第三个字段g.object_name返回一个这样的字符串"gallery_set[blog_posts_attributes][2]",所以我只匹配该字符串中的索引并使用它。
Actually a cooler (and maybe cleaner?) way to do it is to pass a lambda and call it to increment.
实际上,一个更酷(也许更清洁?)的方法是传递一个 lambda 并调用它来递增。
# /controller.rb
index = 0
@incrementer = -> { index += 1}
And the in the view
并且在视图中
<%= 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 %>
回答by gilcierweb
Added to fields_for child_index: 0
添加到 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 %>
回答by MZaragoza
I know that this is a bit late but I recently had to do this you can get the index of the fields_for like this
我知道这有点晚了,但我最近不得不这样做,您可以像这样获得 fields_for 的索引
<% f.fields_for :questions do |builder| %>
<%= render 'some_form', :f => builder, :i => builder.options[:child_index] %>
<% end %>
I hope that this helps :)
我希望这个对你有用 :)
回答by Cruz Nunez
If you want to have control over the indexes check out the indexoption
如果您想控制索引,请查看该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 =>
This will produce
这将产生
<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">
If the form is submitted, params will include something like
如果提交表单,参数将包括类似
{
"thing" => {
"other_things_attributes" => {
"2" => {
"days" => "Mon"
},
"boi" => {
"special_attribute" => "24"
}
}
}
I had to use the index option to get my multi-dropdowns to work. Good luck.
我不得不使用 index 选项来让我的多下拉菜单工作。祝你好运。

