web-dev-qa-db-fra.com

Comment créer plusieurs boutons d'envoi pour le même formulaire dans Rails?

J'ai besoin de plusieurs boutons d'envoi.

J'ai un formulaire qui crée une instance de Contact_Call.

Un bouton le crée normalement.

L'autre bouton le crée mais doit avoir une valeur d'attribut différente de la valeur par défaut, et il doit également définir l'attribut sur un modèle différent, mais lié, utilisé dans le contrôleur.

Comment je fais ça? Je ne peux pas changer l'itinéraire, donc existe-t-il un moyen d'envoyer une variable différente qui est récupérée par [: params]?

Et si je le fais alors, que dois-je faire dans le contrôleur, configurer une déclaration de cas?

91
Timothy T.

Vous pouvez créer plusieurs boutons d'envoi et fournir une valeur différente à chacun:

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

Cela produira:

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

À l'intérieur de votre contrôleur, la valeur du bouton soumis sera identifiée par le paramètre commit. Vérifiez la valeur pour effectuer le traitement requis:

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

Cependant, rappelez-vous que cela couple étroitement votre vue au contrôleur, ce qui peut ne pas être très souhaitable.

125
Anurag

Il existe également une autre approche, utilisant l'attribut formaction sur le bouton d'envoi:

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

Le code reste propre, car le bouton de création standard n'a besoin d'aucune modification, vous insérez uniquement un chemin de routage pour le bouton spécial:

formaction:
L'URI d'un programme qui traite les informations soumises par l'élément d'entrée, s'il s'agit d'un bouton ou d'une image d'envoi. S'il est spécifié, il remplace l'attribut action du propriétaire du formulaire de l'élément . Source: MDN

60
patpir

Vous pouvez également reconnaître le bouton sur lequel vous avez appuyé en modifiant son nom d'attribut.

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

C'est un peu inconfortable car vous devez vérifier la présence des clés params au lieu de simplement vérifier params[:commit] valeur: vous recevrez params[:a_button] ou params[:b_button] selon lequel on a appuyé.

29
masciugo

Solution similaire à celle suggérée par @ vss123 sans utiliser de gemmes:

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

Notez que j'évite d'utiliser la valeur et que j'utilise le nom d'entrée à la place car la valeur du bouton de soumission est souvent internationalisée/traduite. De plus, j'éviterais de l'utiliser trop car cela encombrerait rapidement votre fichier de routes.

12
Tadas Sasnauskas

Nous avons résolu en utilisant contraintes avancées dans Rails.

L'idée est d'avoir le même chemin (et donc la même route & action nommée) mais avec des contraintes de routage vers différentes actions.

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

CommitParamRouting est une classe simple qui a une méthode matches? qui renvoie vrai si le paramètre de validation correspond à l'instance attr donnée. valeur.

Ceci est disponible sous forme de gemme commit_param_matching .

9
siliconsenthil

Une vieille question, mais depuis que je fais face à la même situation, j'ai pensé publier ma solution. J'utilise des constantes de contrôleur pour éviter d'introduire une différence entre la logique du contrôleur et le bouton d'affichage.

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

Et puis dans la vue:

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

De cette façon, le texte ne vit qu'en un seul endroit - en tant que constante dans le contrôleur. Cependant, je n'ai pas encore essayé de comprendre comment i18n.

3
Draknor

J'ai un nombre variable de boutons d'envoi sur mon formulaire grâce à nested_form_fields, donc juste utiliser le nom ne me suffisait pas. J'ai fini par inclure un champ de saisie masqué dans le formulaire et à utiliser Javascript pour le remplir lorsque l'un des boutons de soumission du formulaire a été enfoncé.

1
Shawn Walton