Railsで同じフォームに複数の送信ボタンを作成するにはどうすればよいですか?


97

複数の送信ボタンが必要です。

Contact_Callのインスタンスを作成するフォームがあります。

1つのボタンで通常どおり作成されます。

もう1つのボタンはそれを作成しますが、デフォルトとは異なる:attribute値が必要です。また、コントローラーで使用される別の関連するモデルに属性を設定する必要もあります。

それ、どうやったら出来るの?ルートを変更できないので、[:params]によって取得される別の変数を送信する方法はありますか?

そして、もしそうしたら、コントローラーで何をしますか、caseステートメントをセットアップしますか?



3
これはもっと古く、投票数が多いです。上記のいずれかをこれの複製として閉じる必要がある場合...
Taryn East

回答:


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に感謝!
シュリパッドクリシュナ

1
したがって、「A」を自動的に作成するパラメーターname = 'commit'を置くだけですか?
ティモシーT.

ビューをコントローラーに密結合しないように言った方法はありますか?たとえば、送信ボタンでURLを変更するには、そうです、ボタンの選択がある、それはユーザーの入力、場合eはVEN、HTEコントローラの動作を変更することができ、フォームの提出変数ので、これは必ずしも悪いわけではないということ?
ティモシーT.

1
乱雑なjsハックなしではフォームアクション属性を変更できません。
Ben Orozco

その場でフォームアクション属性を変更することは、より脆弱なソリューションです。commit属性の使用はそれほど重要ではありません。別の方法として、2番目の送信ボタンを別のフォームにラップし、同じアクションに変更する必要があるパラメーターを渡すこともできます。しかし、2つの送信ボタンの値に依存することと大差ありません。これをどのように設定したかがわからなければ、これまでの最善の解決策は、2つの送信ボタンを使用することです。
Anurag

74

送信ボタンのformaction属性を使用する別の方法もあります。

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

標準の作成ボタンは何も変更する必要がないため、コードはクリーンなままです。特別なボタンのルーティングパスを挿入するだけです。

formaction:
入力要素によって送信された情報を処理するプログラムのURI(送信ボタンまたは画像の場合)。指定すると、要素のフォームの所有者のアクション属性をオーバーライドします。出典:MDN



8
私は質問が古いことを理解していますが、この簡潔な解決策はより考慮に値することを読者にアドバイスします。
ジェローム

2
同じ質問があったときに、この答えが見つかれば良かったです。今回はもう少し深く見てみて良かったです。素晴らしいソリューション。
rockusbacchus 2017

1
私はこのソリューションが本当に好きです。ただし、フォームヘルパーをすでに使用しているか、Railsがトークンを受け入れない場合でも、CSRFトークンを使用して非表示フィールドを追加する必要がありました。私はより良い回避策を見つけることができませんでしたが、なぜこれが正確に起こるのか、または単にトークンを追加するだけで修正されるのかはまだわかりません。
イルプトゥンク

これは、単一の責任の原則を尊重し、各ボタンが独自のアクションを実行することを明確にして、コントローラーのロジックをシンプルに保つため、より良いソリューションだと思います。
Khalil Gharbaoui

29

または、属性名を変更してどのボタンが押されたかを認識できます。

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

単にparams[:commit]値を確認するのではなく、paramsキーの存在を確認する必要があるため、少し不快です。どのキーが押されたparams[:a_button]か、またはparams[:b_button]どちらが押されたかに依存します。


2
それでも、コントローラーからビューを分離しません。
slowpoison 2013年

1
はい、分離が意味する最終アクションにルーティングするためにアクションのロジックを回避することを意味する場合、それらはまだ結合されています。そのロジックでname属性を使用する場合、コントローラーはボタンに表示されるものから独立していることを意味しました。ありがとう、編集
masciugo

4
「値」が表示され、Unicode文字を表示している場合は面倒になるため、これはi18nの状況で受け入れられているものよりも優れているようです。
xji

2
ただし、パラメーターは通過できません。simple_form gemを使用しています。相関関係はありますか?
xji

1
これはビューをコントローラーから切り離しませんが、少なくともコントローラーから表示されるテキストを切り離します。はるかに優れたIMO。
Mic Fok 2015年

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

送信ボタンの値は国際化/翻訳されることが多いため、値の使用は避け、代わりに入力名を使用していることに注意してください。また、ルートファイルがすぐに乱雑になるため、あまり使用しないでください。


9

レールの高度な制約を使用して解決しました。

アイデアは同じパス(つまり、同じ名前のルートとアクション)を持つことですが、異なるアクションにルーティングする制約があります。

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

CommitParamRoutingmatches?commit paramが指定されたインスタンス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 %>

このようにして、テキストは1つの場所にのみ存在します-コントローラ内の定数として。ただし、これをi18nに変換する方法はまだわかりません。


「i18n」とはどういう意味ですか?
skrrgwasme 2014

ルートで制約を使用するよりもこれは望ましいことでしたか?ありがとう!
ティモシーT.

@Scott:i18nは「国際化」を意味します-基本的に、どのようにして複数の言語をサポートしますか。私は実際にそれを調べていなかったので、それがどのように機能するか、またはどのようにそれを実装するかについてはあまり詳しくありません。
Draknor 2014

@Angela-おそらく:)そして実際には、コードをリファクタリングした後、無関係なフォームの束を含む単一のモノリシックフォームではなく、それぞれが異なるアクションを持つ複数のフォームを単に作成しました。
Draknor 2014

1

nested_form_fieldsのおかげで、フォームに送信ボタンの数が可変になっているので、名前を使用するだけでは不十分でした。フォームに非表示の入力フィールドを含め、フォームの送信ボタンの1つが押されたときにJavascriptを使用して入力しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.