Rails - 在表单视图中指定属性/动态构建嵌套属性

时间:2012-08-22 10:26:11

标签: ruby-on-rails ruby-on-rails-3

我目前有一个customer表单,其中包含accepted_nested_attributes_for功能。这些功能可以是任意数量的东西,但为了保持简单,我们将假设它们是名字,姓氏和出生日期(我知道这是EAV的问题 - 如果您对此有任何意见,请看到我关于这个问题的另一个问题。)

在我的控制器中,我有:

3.times {@customer.features.build}

这很好用,并构建了3个功能,可以节省预期。但是,我想要为视图中的每个构建特征指定要素类型。我的观点目前看起来像:

<%= customer.fields_for :features do |features_builder| %>
  <%= render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => "First Name", :form_actions_visible => false} %>
<% end -%>

正如人们所料,这会创建3个First Name字段。我想要的是能够指定3种不同类型的功能,如:

<%= customer.fields_for :features do |features_builder| %>
  <%= render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => "First Name", :form_actions_visible => false} %>
  <%= render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => "Last Name", :form_actions_visible => false} %>
  <%= render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => "Date of Birth", :form_actions_visible => false} %>
<% end -%>

显然,上面编写的代码不起作用,因为它试图为每个实例创建3个字段。看起来我需要的是fields_for循环上的一个索引,它允许我遍历并为每个部分添加一个if子句,这样它只会触发一次,并且每个都触发一个不同的特征实例。 / p>

任何人都可以说明我能做到最好吗?搜索之后,我似乎无法找到获取fields_for循环索引的方法。

编辑:根据第一条评论,为清晰起见:我希望在页面上呈现三个功能,一个用于控制器构建的每个功能。我希望每个功能都以不同的方式呈现(传递的是不同的局部变量:上面代码中的fixed_feature_type)。我正在寻找最佳方法。

编辑2:我知道另一种方法是在控制器中动态构建嵌套属性(而不是最初一次构建3) - 有没有办法做到这一点?

编辑3:花了一些时间寻找动态执行此操作的方法,我从Railscast中看到了一个辅助方法,如下所示:

def link_to_add_fields(name, f, association)
  new_object = f.object.class.reflect_on_association(association).klass.new
  fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
    render(association.to_s.singularize + "_fields", :f => builder)
  end
  link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
end

似乎我可以定义一个这样的辅助方法,允许我添加各种功能字段 - 我很乐意将有关如何修改它的建议标记为适合我当前情况的答案。

1 个答案:

答案 0 :(得分:1)

我能够通过将我的部分渲染移动到自定义帮助器来克服这一点,这允许我根据需要动态构建对象。

编辑:根据要求,我的代码如下:

我已将以下代码添加到application_helper.rb文件中:

module ApplicationHelper

  def add_feature_fields(feature_types, object_form_builder, actions_visible)
    feature_types.length.times {object_form_builder.object.features.build}
    i = -1
    object_form_builder.fields_for :features do |features_builder|
      i = i + 1
      render :partial => "features/fixed_feature", :locals => {:feature => features_builder, :fixed_feature_type => feature_types[i], :form_actions_visible => actions_visible}
    end
  end
end

在我看来,我这样称呼这个帮手:

<%= add_feature_fields(["First Name", "Last Name", "Date of Birth"], customer, false) %>

这允许我通过简单地向数组中添加其他项来添加模型所需的多个功能(在本例中为一个人)。

希望这有帮助!

修改:'features / _fixed_feature.html.erb'

<%= feature.hidden_field :feature_type_id, :value => FeatureType.where(:value => fixed_feature_type).first.id %>
<fieldset>
        <div class="control-group">
        <label class="control-label"><Value><%= fixed_feature_type %></label>
        <div class="controls">
            <%= feature.text_field :value, :class => 'input-large' %>
        </div>
    </div>
    <% if form_actions_visible == true %>
        <div class="form-actions">
            <%= content_tag :button, :type => :submit, :class => "btn btn-info" do -%>
                Save Changes
            <% end -%>
            <%= content_tag :button, :type => :cancel, :class => "btn btn-warning" do -%>
                Cancel
            <% end -%>
        </div>
    <% end %>
</fieldset>

没有什么特别之处,只需要通过助手传入的局部变量来渲染标签等,而不需要“特征类型”框,然后是一个值框(它只渲染一个值框,因此类型是固定)。

根据您的评论,如果您想为不同的模型添加功能,您只需再次调用帮助程序并更改“客户”部分(这是表单构建器 - 更常见的是这是'f'但我更喜欢语义命名)。