Rails 3 - 远程表单提交后指定表单操作

时间:2013-01-16 13:13:50

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

我有一个非常简单的表单,在我尝试重新提交之前一切正常。之后,它会更新记录而不是创建新记录:

在我看来,我有这个:

#new_order_form
  = render 'form'

我的形式偏:

= semantic_form_for [@location, @order], :remote => true do |f|
  -if @order.errors.any?
    #notice{:class=>'alert alert-block alert-error fade in'}
      %a{:class=>"close", :data=>{:dismiss=>"alert", :href=>"#"}}
        x
      %h3  
        = pluralize(@order.errors.count, "error")
      - @order.errors.full_messages.each do |msg|
        = msg
        %br

  %table{:class => 'table table-bordered', :style=> {width: '50%'}}  
    %tr
      %td= f.text_field :product_order_id, :placeholder => "Order ID"

在我的create.js中:

$("#new_order_form").html("<%= escape_javascript(render("form")) %>");

这适用于创建订单并在错误存在时呈现错误。

问题是:如果我在不刷新页面的情况下输入其他订单号,它会更新以前创建的记录,而不是创建新记录。

查看表单代码,我可以看到提交操作被替换为更新。

我试图用这个替换代码:

 = semantic_form_for [@location, @order], :remote => true do |f|
   #new_order_form
     = render 'form', :f => f

这在create.js

$("#new_order_form").html("<%= escape_javascript(render :partial => 'form', :locals => {:f => @order}) %>");

这也不起作用并抱怨text_field无效。

最好的方法是什么?感谢

3 个答案:

答案 0 :(得分:1)

我不熟悉semantic_form_for,但我认为它是常规form_for的超集。

form_for的工作方式是检查模型是否持久化,然后将默认值与之匹配。我个人认为从form_for操作中调用edit会假设为update,但事实并非如此。 form_for将假定任何未加载模型的操作为create,任何持久模型的操作为update。如果你愿意的话,我相信你可以覆盖它,但我自己没有尝试过。

听起来你可能正在做的是展示模型并尝试在同一页面上创建新模型。 (如果我错了,请包含您的控制器,因为很难说出您打算做什么。)您的控制器可能需要@show_order@new_order

我希望这有帮助,如果没有,也许您可​​以提供有关控制器的更多详细信息。

修改

每当您希望能够创建新模型时,您需要确保控制器调用@new_order = Order.new并确保使用form_for调用@new_ordernew_只是一个区分新的和旧的前缀。

在这种情况下,我不确定控制器是order#show还是order#create的成功部分。

对于show,您需要这样的内容:

@order = Order.find(params[:id])
@new_order = Order.new

如果您从create中执行此操作,则可能需要:

@order = Order.new(params[:order])

if @order.save
  @new_order = Order.new
  redirect_to ???
else
  render :new
end

以上所有内容应与库存控制器完全匹配,但添加@new_order除外。 (换句话说,如果它们在那里,请不要删除respond_toformat行。)

答案 1 :(得分:1)

问题是你的create.js正在读取来自创建操作结果的@order,这是现有的@order,因此它变成了更新。

一个修复:在'if @ order.save'创建部分中创建一个新的@order:@ order_new = Order.new。

现在告诉你的表单部分使用order而不是@order with:

semantic_form_for [@location, order], :remote => true do |f|

使用以下命令更新您的create.js:

$("#new_order_form").html("<%= escape_javascript(render 'form', :order => @order_new) %>");

确保更新引用表单呈现的任何内容以使用:order =&gt; @订购。例如:

<%= render 'form', :order => @order %>

如果你的@location需要是一个新实例,那么同样的规则也适用。

我使用@order_new而不是覆盖@order,以防你想在create.js中使用@order做一些事情

旁注(对于其他观看者): Rails 3.x渲染方法不需要partials =&gt;和locals =&gt;助手。

答案 2 :(得分:1)

我不是这方面的专家,但亚当的回答似乎是正确的。我假设您在控制器操作中有类似下面的内容:

def create
  @order = Order.new(params[:order])

  if @order.save
    responds_to do |format|
      format.js
      format.html { redirect_to 'xxx' }
    end
  else
    responds_to do |format|
      format.js
      format.html { render :new }
    end
  end
end

如果你有上面的结构,那么create.js.erb只是传递@order.save调用后修改过的@order对象。您可以在传递的条件中重新定义它,如下所示(检查第4行):

def create
  @order = Order.new(params[:order])

  if @order.save
    @order = Order.new
    responds_to do |format|
      format.js
      format.html { redirect_to 'xxx' }
    end
  else
    responds_to do |format|
      format.js
      format.html { render :new }
    end
  end
end

现在如果@order已成功保存,将创建并传递新订单。否则将传递带有验证错误的旧@order。希望这会有所帮助。