如何在Rails中为同一表单创建多个提交按钮?

Tim*_* T. 91 ruby ruby-on-rails form-submit

我需要有多个提交按钮.

我有一个表单,它创建一个Contact_Call实例.

一个按钮正常创建它.

另一个按钮创建它但需要具有默认的不同:属性值,并且还需要在控制器中使用的不同但相关的模型上设置属性.

我怎么做?我无法改变路线,所以有没有办法发送一个由[:params]拾取的另一个变量?

如果我这样做,我在控制器中做什么,设置一个案例陈述?

Anu*_*rag 125

您可以创建多个提交按钮,并为每个按钮提供不同的值:

<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A' %>
    <%= f.submit 'B' %>
    ..
<% end %>
Run Code Online (Sandbox Code Playgroud)

这将输出:

<input type="submit" value="A" id=".." name="commit" />
<input type="submit" value="B" id=".." name="commit" />
Run Code Online (Sandbox Code Playgroud)

在控制器内部,提交的按钮的值将由参数标识commit.检查值以执行所需的处理:

def <controller action>
    if params[:commit] == 'A'
        # A was pressed 
    elsif params[:commit] == 'B'
        # B was pressed
    end
end
Run Code Online (Sandbox Code Playgroud)

但是,请记住,这会将您的视图与控制器紧密耦合,这可能并不是非常理想.


小智 63

还有另一种方法,使用提交按钮上的formaction属性:

<% form_for(something) do |f| %>
    ...
    <%= f.submit "Create" %>
    <%= f.submit "Special Action", formaction: special_action_path %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

代码保持干净,因为标准的创建按钮不需要任何更改,您只需为特殊按钮插入路由路径:

formaction:
处理输入元素提交的信息的程序的URI,如果它是提交按钮或图像.如果指定,它将覆盖元素表单所有者的action属性.资料来源:MDN

  • 我意识到这个问题已经过时了,但我建议读者这个简洁的解决方案应该得到更好的考虑. (5认同)
  • 所有浏览器都支持此功能 http://www.w3schools.com/tags/att_button_formaction.asp http://www.w3schools.com/tags/att_input_formaction.asp (3认同)
  • 我希望我第一次遇到同样的问题时就找到了这个答案。我很高兴这次决定更深入地研究。很好的解决方案。 (2认同)
  • 我真的很喜欢这个解决方案。但是,即使我已经在使用表单助手,我也必须使用 CSRF 令牌添加隐藏字段,否则 Rails 不会接受该令牌。我找不到更好的解决方法,并且仍然不确定为什么会发生这种情况,或者只是再次添加令牌即可修复它。 (2认同)

mas*_*ugo 29

您也可以识别按下哪个按钮更改其属性名称.

<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A', name: 'a_button' %>
    <%= f.submit 'B', name: 'b_button' %>
    ..
<% end %>
Run Code Online (Sandbox Code Playgroud)

这有点不舒服,因为你必须检查params键存在而不是简单地检查params[:commit]值:你将接收params[:a_button]params[:b_button]取决于按下哪一个.

  • 这个似乎比i18n情况下接受的更好,因为显示"值",如果你显示Unicode字符,它会变得混乱. (4认同)
  • 仍然没有将视图与控制器分离。 (2认同)
  • 然而,参数并没有被允许通过。我正在使用 simple_form gem。有没有相关性。 (2认同)

Tad*_*kas 13

与@ vss123建议的类似解决方案,不使用任何宝石:

resources :plan do
  post :save, constraints: lambda {|req| req.params.key?(:propose)}, action: :propose
  post :save, constraints: lambda {|req| req.params.key?(:finalize)}, action: :finalize
end
Run Code Online (Sandbox Code Playgroud)

请注意,我避免使用值并使用输入名称,因为提交按钮值通常是国际化/翻译.此外,我会避免使用太多,因为它会很快混乱你的路线文件.


sil*_*hil 9

我们在rails中使用了高级约束来解决.

我们的想法是拥有相同的路径(因此具有相同的命名路由和操作),但约束路由到不同的操作.

resources :plan do
  post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
  post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end
Run Code Online (Sandbox Code Playgroud)

CommitParamRouting是一个简单的类,有一个方法matches?,如果commit参数匹配给定的实例attr,则返回true.值.

这可用作gem commit_param_matching.