H O*_*H O 20 activerecord ruby-on-rails ruby-on-rails-3 cocoon-gem
我目前有一个带有深度嵌套的复杂形式,我正在使用Cocoon gem来根据需要动态添加部分(例如,如果用户想要在销售表单中添加其他车辆).代码如下所示:
<%= sale.fields_for :sale_vehicles do |sale_vehicles_builder| %>
<%= render :partial => "sale_vehicles/form", :locals => {:f => sale_vehicles_builder, :form_actions_visible => false} %>
<% end -%>
<div class="add-field-links">
<%= link_to_add_association '<i></i> Add Vehicle'.html_safe, sale, :sale_vehicles, :partial => 'sale_vehicles/form', :render_options => {:locals => {:form_actions_visible => 'false', :show_features => true, :fieldset_label => 'Vehicle Details'}}, :class => 'btn' %>
</div>
Run Code Online (Sandbox Code Playgroud)
这对于第一级嵌套非常有效 - sale_vehicle对象由Cocoon正确构建,并且表单按预期呈现.
当存在另一级嵌套时问题出现 - sale_vehicle部分看起来像这样:
<%= f.fields_for :vehicle do |vehicle_builder| %>
<%= render :partial => "vehicles/form", :locals => {:f => vehicle_builder, :f_parent => f, :form_actions_visible => false, :show_features => true, :fieldset_label => 'Vehicle Details'} %>
<% end -%>
Run Code Online (Sandbox Code Playgroud)
vehicle没有字段渲染的部分,因为没有sale_vehicle.vehicle构建任何对象.
我需要做的是构建嵌套对象和主对象(Cocoon目前不构建任何嵌套对象),但是如何最好地做到这一点?有没有办法从帮助程序代码中选择嵌套表单,以便可以构建这些表单?
Cocoon目前正在构建这样的主要对象:
if instance.collection?
f.object.send(association).build
else
f.object.send("build_#{association}")
end
Run Code Online (Sandbox Code Playgroud)
如果我可以执行类似下面的操作,它会使事情变得简单明了,但我不确定如何获取f.children- 有没有办法从父窗体构建器访问嵌套窗体构建器?
f.children.each do |child|
child.object.build
end
Run Code Online (Sandbox Code Playgroud)
任何帮助,以使这个工作,或建议动态构建这些对象的另一种方式.
谢谢!
编辑:可能值得一提的是,这个问题似乎与上面提到的Cocoon gem以及Ryan Bates的nested_form gem都有关.Cocoon gem的问题#91似乎与此问题相同,但dnagir建议的解决方法(委托对象的构建)在这种情况下并不理想,因为这会导致其他形式的问题.
nat*_*vda 27
我可以在你的第二个嵌套形式中看到没有link_to_add_association.
在cocoon中,link_to_add_association当用户想要动态添加它时,它会构建一个新元素.
或者,你暗示一旦sale_vehicle建成,它应该自动包含vehicle?我认为用户必须选择出售的车辆?
我有一个测试项目,演示了双嵌套表单:项目有任务,可以有子任务.
但也许这与你想做的事情没有足够的关系?
你没有展示你的模型,但如果我理解正确的关系
sale
has_many :sale_vehicles
sale_vehicle
has_one :vehicle (has_many?)
Run Code Online (Sandbox Code Playgroud)
所以,如果你有一个sale_vehicle可以拥有的vehicle,那么我会假设你的用户首先添加sale_vehicle到sale然后,点击链接添加vehicle.这就是茧能做得非常好的事情.另一方面,如果你想在cocoon动态创建a时创建a sale_vehicle,那么vehicle我会看到一些不同的选项.
after_initialize不能说我是这个的真正粉丝,但在after_initialize你的回调中sale_vehicle,你总能建立所需的vehicle模型.
我假设在这里,因为你的sale_Vehicle无效/不能没有存在的vehicle模型,它是模型的责任立即创建嵌套模式上构建.
请注意,每个对象创建after_initialize都会执行,因此这可能会很昂贵.但这可能是一个快速解决方案.如果你拒绝空的嵌套模型,这应该适用于imho.
对于用户来说,sale_vehicle并vehicle似乎一个对象,那么为什么不创建一个装饰,一个sale_vehicle和车辆,其呈现为一个(嵌套)格式和保存这个时候,装饰知道它需要被保存到正确的组成楷模.
注意:对此有不同的用语.装饰器通常只使用一些视图方法扩展单个类,但它也可以是不同模型的组合.替代术语:演示者,视图模型.
无论如何,装饰器/演示者的功能是为用户抽象出基础数据模型.因此,无论出于何种原因,您需要将单个实体拆分为两个数据库模型(例如,限制列的nr,以保持模型可读,......)但对于用户而言,它仍然是单个实体.所以"呈现"它作为一个.
build方法不确定我是否是这个的粉丝,但这绝对是一种可能性.如果"嵌套模型"不是ActiveRecord :: Association,则已经支持它,所以这不应该太难添加.但我对这一补充犹豫不决.所有这些选项使其更加复杂.
在你的局部内部只需构建所需的子对象.这必须在之前发生fields_for,然后你就好了.就像是
<% f.object.build_vehicle %>
<%= f.fields_for :vehicle do |vehicle_builder| %>
<%= render :partial => "vehicles/form", :locals => {:f => vehicle_builder, :f_parent => f, :form_actions_visible => false, :show_features => true, :fieldset_label => 'Vehicle Details'} %>
<% end -%>
Run Code Online (Sandbox Code Playgroud)
我个人非常喜欢装饰器方法,但它可能有点沉重.只需在渲染调用之前构建对象fields_for,这样您始终确定至少有一个.
我很想听听你的想法.
希望这可以帮助.