有许多资源处理Rails表单和简单的ajax crud接口,如那些着名的Post - >评论示例。但是,我的问题有点复杂,我似乎无法让它发挥作用。
我有一个订单表单,可以包含几个line_items。在ryan bates借助nested_form gem提交任何内容之前,添加和删除了这些line_items。这一切都很好,它完美无瑕。
现在我想添加一些动态行为。当某些line_item输入字段更改总计时,应更新其他计算。为该line_item选择其他产品时,应在提交表单之前更新并显示其价格。类似的东西。我的第一种方法是在JavaScript中进行这些计算,在工作的同时,我很快意识到我将我在应用程序模型中定义的所有逻辑加倍。另外,由于您无法访问实例变量,因此在JS中执行此操作非常麻烦。
经过一番思考后,我想在有人更改某些输入值后立即提交并刷新这些fields_for line_item partials。这应该是基本的工作流程:
用户输入 - >提交订单(如果可能,只提交line_item) - >返回更新的line_item部分,刷新计算等。
将来我想将此行为扩展到不再需要保存按钮的位置。
但是我不想重新渲染整个表单(对于快速用户输入来说太慢),只是当前的fields_for partial。
问题是每当我限制我的js响应重新渲染当前fields_for partial时,form_for @order do |f|
所需的f变量就会丢失。如果我在我的回复中替换整个表单,它工作正常。
这是当前的代码:
/views/orders/_form.html.slim
= nested_form_for @order do |f|
...
#line-items
= f.fields_for :line_items do |line_item|
= render "orders/line_item_fields", f: line_item
...
视图/命令/ _line_item_fields.html.slim
...
= f.label :product_id, "Product"
= f.collection_select(:product_id, Product.order(:name), :id, :name, class: "order_line_items_product_id submittable" )
= f.label :quantity
= f.text_field :quantity, class: "submittable"
= f.label :price
= f.text_field :price, class: "submittable"
...
.totals
p
span = f.object.total_price
/app/assets/javascripts/orders.js.erb
$('body').on('change', '.submittable', function () {
var current_item = $(this).closest('section')
var order_id = $('form.edit_order').data('order-id')
var data = $('form.edit_order').serialize();
current_item.addClass('item-to-refresh')
$.ajax({
url: "/orders/" + order_id,
data: data,
dataType: "script",
type: "patch",
error: function(response) {
response
},
success: function(response){
response
}
});
}
/app/controllers/orders_controller.rb
...
def update
@order = Order.find(params[:id])
authorize @order
if @order.update_attributes(order_params)
respond_to do |format|
format.html do
redirect_to order_path
flash[:success] = "Order #{@order.id} saved"
end
format.js
end
else
render 'edit'
end
end
...
/app/views/orders/update.js.erb
$('.item-to-refresh').replaceWith("<%= j render 'orders/line_item_fields' %>")
如上所述,响应总是伴随错误ActionView::Template::Error (undefined local variable or method 'f' for #class...
- 我知道它需要f变量,但我该如何传递它?我尝试将主题中的f: f
,f: line_item
和类似变体添加到 update.js.erb 的渲染功能,但没有成功。当然,如果我不尝试在响应中呈现表单元素而只是简单的<p>It works!</p>
此外,我在脑海中想到的一般概念是处理网络应用中交互性的好方法吗?这仍然是一个老式的基于文档/页面的应用程序,其中重新加载页面就好了。但对于应用程序的某些部分,用户只希望得到即时反馈和结果 - 点击“保存”以获得一些计算和总计这些天是不够的。 另一方面(除非上面的代码没有告诉你)我讨厌Javascript,并希望在解决这些问题时尽量减少它。所以,我想找到一种可重用的方法来提交和刷新有关变更事件的部分内容。
答案 0 :(得分:0)
试试这个
= render "orders/line_item_fields", :locals => {f: line_item}
或
= render partial: "orders/line_item_fields", :locals => {f: line_item}
答案 1 :(得分:0)
我知道已经有点晚了,但是我有一个同样的问题,我想在更新记录而不呈现完整的表单之后重新呈现fields_for表单。
我的解决方案是在更新(并在数据库中创建记录)后,更改由javascript动态创建的具有正确ID和名称的每个输入(选择,复选框等)的ID和名称属性。最后,动态字段看起来像是由表单构建器为编辑字段创建的字段。
除了更改id和name属性外,在fields_for表单元素之后还需要一个额外的输入type = hiddened字段。这还需要正确的ID和名称语法,例如表单中的字段,并且value属性必须是新的记录ID。
希望这会有所帮助!