Rails: 在一个表单中使用多个提交按钮

69

假设我有一个文章模型,而在文章的“新建”视图中我有两个按钮,“发布”和“保存草稿”。

我的问题是如何在控制器中知道哪个按钮被点击。

我已经有一个解决方案,但我认为一定有更好的方法。我目前在视图中使用的是:

<div class="actions">
  <%= f.submit "Publish" %>
  <%= f.submit "Save Draft", :name => "commit" %>
</div>

所以在控制器中,我可以使用 params[:commit] 字符串来处理该动作。

def create
  @article = Article.new(params[:article])
  if params[:commit] == "Publish"
    @article.status = 'publish'
    // detail omitted
  end

  @article.save
end

但我认为使用与视图相关的字符串并不好。你能告诉我另一种方法来实现这个吗?

更新:由于这些按钮在同一个表单中,它们都将进入“创建”操作,这对我来说是可以的。我想做的是在“创建”操作中处理它,例如给文章模型添加一个“状态”列并保存“公共”或“草稿”。


1
可能是重复的问题:如何在Rails中为同一表单创建多个提交按钮? - Taryn East
6个回答

80

这个问题在Railscast第38集中有讲到。使用params哈希来检测哪个按钮被点击是正确的方法:

视图:

<%= submit_tag 'Create' %>
<%= submit_tag 'Create and Add Another', name: 'create_and_add' %>

控制器:

if params[:create_and_add]
  # Redirect to new form, for example.

else
  # Redirect to show the newly created record, for example.
end

我已经观看了一周的Railscasts视频,但我肯定错过了这个。它似乎与我的代码相同,都使用params哈希表,但它做得更好,我也改进了我的代码。非常感谢! - kinopyo
如果您有一个在“新建”和“编辑”操作中都使用的“_form”部分,则情况会变得非常复杂。在这种情况下,您必须在“创建”和“更新”操作中设置上述控制器逻辑,以考虑用户正在创建新对象或编辑现有对象的情况。 - jayp
@jayp,这是我现在正在尝试做的事情,很想听听您对我的问题的看法。 - mbigras

9

也可以在form_for助手上这样完成

 <%= f.submit "Publish",name: "publish", class: "tiny button radius success" %>
 <%= f.submit 'Mark as Draft', name: "draft", class: "tiny button radius " %>

控制器上的逻辑也是相同的。

   if params[:publish]
      // your code
   elsif params[:draft]
      // your code
   end

8
我们在Rails中使用高级约束解决了问题。
这个想法是有相同的路径(因此具有相同的命名路由和操作),但通过不同的约束路由到不同的操作。
resources :plan do
  post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
  post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end

CommitParamRouting 是一个简单的类,它有一个方法 matches?,如果提交参数与给定实例属性值匹配,则返回 true。

这可作为 gem commit_param_matching 使用。


这太棒了。它解决了使用POST方法无法重定向的问题。 - urmurmur

1

我记得曾经遇到过这个问题。你不能保留两个按钮,然后根据params[:commit]调用某些操作。提交按钮的onclick将调用表单引用的URL。有一些不好的方法可以获得所需的行为。保留一个按钮来调用表单引用的操作,并获得另一个按钮来调用操作,我使用了link_to,然后更改样式以匹配按钮。此外,您还可以使用jQuery更改表单将调用的URL,从而决定在运行时调用哪个操作。希望这可以帮助到您。


抱歉,我忘了提到我正在尝试在同一个创建操作中处理它,我已经更新了问题。但我也学到了如何使用jQuery更改表单的URL的技巧,这很有帮助。谢谢。 - kinopyo
这个问题的唯一答案对我有用,它确实在控制器中使用params[:commit]的值来区分按下了哪个按钮。当在视图中定义提交按钮为<%= submit_tag( "X" ) %>时,该字符串为“X”。 - Teemu Leisti

0
通常我会使用John Topley提供的建议(请参见上面的答案)。 另一种方法是使用JQuery / JS更改表单操作属性-在单击提交按钮时 示例:
form_tag({} ,:method => 'post', :id => 'reports_action') do 
   .......
   ....... 
  submit_tag 'submit',  :onclick => "return changeAction();"
end

然后......

function changeAction(){
   $('#reports_action').attr('action','my_new_action');
}   

0

您还可以在提交按钮上设置一些data属性,并使用JavaScript在单击其中一个按钮时更改form操作


在移动设备上,“tap”怎么办? - sambehera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接