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


98

我需要有多个提交按钮。

我有一个创建Contact_Call实例的表单。

一键创建它正常。

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

我怎么做?我无法更改路线,因此有没有办法发送由[:params]接收的其他变量?

如果这样做,我将在控制器中做什么,设置一个case语句?



3
这个年龄较大,票数更高。如果有上述内容,应关闭此副本作为副本...
Taryn East 2015年

Answers:


129

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

<% form_for(something) do |f| %>
    ..
    <%= f.submit 'A' %>
    <%= f.submit 'B' %>
    ..
<% end %>

这将输出:

<input type="submit" value="A" id=".." name="commit" />
<input type="submit" value="B" id=".." name="commit" />

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

def <controller action>
    if params[:commit] == 'A'
        # A was pressed 
    elsif params[:commit] == 'B'
        # B was pressed
    end
end

但是,请记住,这可能会使视图与控制器紧密耦合,这可能不是很理想。


1
现在,那是新的东西。谢谢@Anurag!
Shripad Krishna

1
所以只需要把'A'自动创建为参数name ='commit'?
Timothy T.

您说过有没有办法不将视图紧密耦合到控制器?例如,用于提交按钮来更改URL?它似乎,这不一定是坏事,因为一个表单提交的变量可以改变兴田控制器的行为,例如如果用户输入VEN,该按钮的选择是什么?
蒂莫西

1
没有凌乱的js hack,您就无法更改表单操作属性。
Ben Orozco 2010年

动态更改表单动作属性是一种更脆弱的解决方案。使用commit属性的情况要少一些。您也可以将第二个提交按钮包装在不同的表单中,并传递需要更改为相同操作的参数。但这与依赖2个提交按钮的值没有太大不同。在不了解您如何设置此东西的情况下,迄今为止最好的解决方案是使用2个提交按钮。
阿努拉格

75

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

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

代码保持整洁,因为标准的create按钮不需要任何更改,您只需为特殊按钮插入一个路由路径即可:

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



8
我意识到这个问题已经老了,但是我建议读者,这个简洁的解决方案值得更好的考虑。
杰罗姆

2
我希望我第一次遇到同样的问题时就找到了这个答案。我很高兴这次决定更深入一点。很好的解决方案。
rockusbacchus

1
我真的很喜欢这个解决方案。但是,即使我已经在使用表单帮助程序,否则我也必须在CSRF令牌中添加一个隐藏字段,否则Rails将不接受该令牌。我找不到更好的解决方法,仍然不确定为什么会发生这种情况,或者只是再次添加令牌即可解决该问题。
irruputuncu

我认为这是更好的解决方案,因为它尊重单一责任原则,并且让事情保持清晰,每个按钮都执行自己的动作,从而使控制器中的逻辑保持简单。
Khalil Gharbaoui

29

您也可以识别更改属性名称的按下按钮。

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

这有点不舒服,因为您必须检查参数键的存在而不是简单地检查params[:commit]值:您将收到params[:a_button]params[:b_button]取决于按下哪个键。


2
仍然不会将视图与控制器分离。
慢毒

1
是的,如果解耦意味着在操作中避免某些逻辑以便路由到您正确的最终操作,那么它们仍然是耦合的。我只是说,如果您在该逻辑中使用name属性,则控制器将独立于按钮上显示的内容。谢谢,编辑
masciugo 2013年

4
在i18n情况下,此字符似乎比公认的字符要好,因为会显示“值”,并且如果显示的是Unicode字符,则会变得混乱。
xji 2015年

2
但是,这些参数未被允许通过。我正在使用simple_form gem。有没有相关性。
xji 2015年

1
这不会使视图与控制器脱钩,但至少它会与控制器上显示的文本脱钩。更好的IMO。
Mic Fok 2015年

13

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

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

注意,我避免使用值,而改用输入名称,因为提交按钮的值通常是国际化的/翻译的。另外,我会避免使用过多,因为它会很快使您的路线文件混乱。


9

我们解决了在Rails中使用高级约束的问题。

想法是具有相同的路径(因此也具有相同的命名路线和动作),但具有路由到不同动作的约束。

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

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

这可以作为gem commit_param_matching使用


3

一个古老的问题,但是由于我一直在处理相同的情况,所以我认为我应该发布解决方案。我使用控制器常量来避免在控制器逻辑和视图按钮之间引入差异。

class SearchController < ApplicationController
  SEARCH_TYPES = {
    :searchABC => "Search ABCs",
    :search123 => "Search 123s"
  }

  def search
    [...]
    if params[:commit] == SEARCH_TYPES[:searchABC]
      [...]
    elsif params[:commit] == SEARCH_TYPES[:search123]
      [...]
    else
      flash[:error] = "Search type not found!"]
      [...]
    end
  end
  [...]          
end

然后在视图中:

<% form_for(something) do |f| %>
    [...]
    <%= f.submit SearchController::SEARCH_TYPES[:searchABC] %>
    <%= f.submit SearchController::SEARCH_TYPES[:search123] %>
    [...]
<% end %>

这样,文本仅存在于一个位置-作为控制器中的常量。但是,我还没有想出如何进行此操作。


“ i18n”是什么意思?
skrrgwasme 2014年

这比在路径中使用约束更好吗?谢谢!
Timothy T.

@斯科特:i18n的意思是“国际化”-基本上,您将如何支持多种语言。我还没有真正研究过它,所以我对它的工作方式或实现方式不是很熟悉。
德拉诺2014年

@Angela-可能不是:)实际上,在重构代码后,我只是创建了多种形式,每种形式具有不同的动作,而不是包含一堆不相关形式的单一整体形式。
德拉诺2014年

1

多亏了nested_form_fields,表单上的提交按钮数量有所变化,因此仅使用名称对我来说还不够。我最终在表单中包含一个隐藏的输入字段,并在按下表单提交按钮之一时使用Javascript来填充它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.