有没有一种方法(或者类似的功能)可以使用fields_for_with_index
?
例如:
<% f.fields_for_with_index :questions do |builder, index| %>
<%= render 'some_form', :f => builder, :i => index %>
<% end %>
正在呈现的部分需要知道在fields_for
循环中当前索引是什么。
有没有一种方法(或者类似的功能)可以使用fields_for_with_index
?
例如:
<% f.fields_for_with_index :questions do |builder, index| %>
<%= render 'some_form', :f => builder, :i => index %>
<% end %>
正在呈现的部分需要知道在fields_for
循环中当前索引是什么。
f.options
参数。因此,在渲染的_some_form.html.erb
文件中,可以这样访问索引:<%= f.options[:child_index] %>
你不需要做任何其他事情。
更新:看起来我的答案不够清楚...
原始的HTML文件:
<!-- Main ERB File -->
<% f.fields_for :questions do |builder| %>
<%= render 'some_form', :f => builder %>
<% end %>
子表单呈现:
<!-- _some_form.html.erb -->
<%= f.options[:child_index] %>
<%= f.options[:child_index] %>
,而不是在原始的“builder”中。回答已更新以提供更多说明。 - Sheharyarnil
。 - bcackerman截至Rails 4.0.2,FormBuilder对象现在包含一个索引:
https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-fields_for
例如:
<%= form_for @person do |person_form| %>
...
<%= person_form.fields_for :projects do |project_fields| %>
Project #<%= project_fields.index %>
...
<% end %>
...
<% end %>
project_fields.options[:child_index]
更简洁。所以我更喜欢这种方式! - HighHopes下面的回答是多年前发布的,现代方法请参见: https://dev59.com/G2445IYBdhLWcg3wcaAN#22640703
实际上,以下方法更好,更贴近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 %>
来源于: http://railsapi.com/doc/rails-v3.0.4/classes/ActionView/Helpers/FormHelper.html#M006456
你也可以指定要使用的实例:
<%= 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 %>
适用于Rails 4或以上版本
<%= form_for @person do |person_form| %>
<%= person_form.fields_for :projects do |project_fields| %>
<%= project_fields.index %>
<% end %>
<% end %>
针对Rails 3的猴子补丁支持
为了使得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
.index
,这样会更简洁。 - Lucas Andrade请查看渲染一组局部视图。如果您的需求是模板需要迭代一个数组,并为每个元素呈现一个子模板。
<%= f.fields_for @parent.children do |children_form| %>
<%= render :partial => 'children', :collection => @parent.children,
:locals => { :f => children_form } %>
<% end %>
这将渲染“_children.erb”并将本地变量'children'传递给模板进行显示。迭代计数器将自动提供给模板,名称形式为partial_name_counter
。在上面的示例中,模板将使用children_counter
。
希望这可以帮助到您。
question_comment_form
是我的部分名称... - Shpigford我发现在Rails提供的方式中,至少在-v3.2.14版本中,没有一个像样的方法可以解决这个问题。
@Sheharyar Naseer提到了可以使用选项哈希来解决这个问题,但是我认为他所建议的方式并不能实现。
我尝试了如下做法 =>
<%= 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 %>
或者
<%= 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 %>
在我的情况下,g.object_name
返回一个字符串,类似于这样的 "gallery_set[blog_posts_attributes][2]"
,对于第三个呈现的字段,所以我只需要匹配该字符串中的索引并使用它。
实际上,更酷(也可能更干净?)的方法是传递一个 lambda 并调用它来增加。
# /controller.rb
index = 0
@incrementer = -> { index += 1}
在视图中
<%= 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 %>
已添加到 fields_for 子索引:0
<%= form_for @person do |person_form| %>
<%= person_form.fields_for :projects, child_index: 0 do |project_fields| %>
<%= project_fields.index %>
<% end %>
<% end %>
我知道可能有点晚了,但最近我必须这样做,你可以像这样获取fields_for的索引
<% f.fields_for :questions do |builder| %>
<%= render 'some_form', :f => builder, :i => builder.options[:child_index] %>
<% end %>
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 =>
这将产生
<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">
如果表单已提交,参数将包含类似以下内容
{
"thing" => {
"other_things_attributes" => {
"2" => {
"days" => "Mon"
},
"boi" => {
"special_attribute" => "24"
}
}
}
我不得不使用索引选项来使我的多下拉框正常工作。祝你好运。