Come posso creare più pulsanti di invio per lo stesso modulo in Rails?


97

Ho bisogno di più pulsanti di invio.

Ho un modulo che crea un'istanza di Contact_Call.

Un pulsante lo crea normalmente.

L'altro pulsante lo crea ma deve avere un valore di attributo diverso da quello predefinito e deve anche impostare l'attributo su un modello diverso ma correlato utilizzato nel controller.

Come lo faccio? Non posso cambiare il percorso, quindi c'è un modo per inviare una variabile diversa che viene rilevata da [: params]?

E se lo faccio allora, cosa devo fare nel controller, impostare una dichiarazione del caso?



3
Questo è più vecchio e ha più voti. Semmai quanto sopra dovrebbe essere chiuso come un duplicato di questo ...
Taryn East

Risposte:


129

Puoi creare più pulsanti di invio e fornire un valore diverso a ciascuno:

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

Questo produrrà:

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

All'interno del controller, il valore del pulsante inviato sarà identificato dal parametro commit. Controlla il valore per eseguire l'elaborazione richiesta:

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

Tuttavia, ricorda che questo accoppia strettamente la tua vista al controller, il che potrebbe non essere molto desiderabile.


1
Questo è qualcosa di nuovo. Grazie @Anurag!
Shripad Krishna,

1
quindi semplicemente mettendo la 'A' crei automaticamente nome parametro = 'commit'?
Timothy T.

c'è un modo come hai detto per non accoppiare strettamente la vista al controller? ad esempio, per i pulsanti di invio per modificare l'URL? E sembra che questo non è necessariamente un male, perché a variabili di modulo sottopone che possono cambiare il comportamento del controllore HTE, nche se l'input dell'utente, che la selezione del pulsante è?
Timothy T.

1
Non è possibile modificare un attributo di azione del modulo senza un hack js disordinato.
Ben Orozco

Cambiare al volo l'attributo di azione del modulo è una soluzione più fragile. L'uso dell'attributo commit lo è meno. In alternativa, potresti racchiudere il secondo pulsante di invio in un modulo diverso e passare un parametro che deve essere modificato alla stessa azione. Ma non è molto diverso dall'affidarsi ai valori dei 2 pulsanti di invio. Senza sapere di più su come hai impostato questa cosa, la soluzione migliore finora sarebbe con 2 pulsanti di invio.
Anurag

74

C'è anche un altro approccio, utilizzando l'attributo formaction sul pulsante di invio:

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

Il codice rimane pulito, poiché il pulsante di creazione standard non necessita di alcuna modifica, inserisci solo un percorso di instradamento per il pulsante speciale:

formaction:
L'URI di un programma che elabora le informazioni inviate dall'elemento di input, se si tratta di un pulsante di invio o di un'immagine. Se specificato, sovrascrive l'attributo action del proprietario del modulo dell'elemento . Fonte: MDN



8
Mi rendo conto che la domanda è vecchia, ma consiglio ai lettori che questa soluzione concisa merita maggiore considerazione.
Jerome

2
Vorrei aver trovato questa risposta la prima volta che ho avuto la stessa domanda. Sono contento di aver deciso di guardare un po 'più in profondità questa volta. Ottima soluzione.
rockusbacchus

1
Mi piace molto questa soluzione. Tuttavia, ho dovuto aggiungere un campo nascosto con il token CSRF anche se stavo già utilizzando gli helper del modulo o Rails non avrebbe accettato il token. Non sono riuscito a trovare una soluzione migliore e non sono ancora sicuro del motivo per cui ciò accade esattamente o semplicemente aggiungendo di nuovo il token lo risolve.
irruputuncu

Penso che questa sia la soluzione migliore perché rispetta i principi della singola responsabilità e mantiene le cose chiare ogni pulsante esegue la propria azione mantenendo la logica nei controller semplice.
Khalil Gharbaoui

29

In alternativa è possibile riconoscere quale pulsante è stato premuto cambiando il nome dell'attributo.

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

È un po 'scomodo perché devi controllare la presenza dei tasti dei parametri invece di controllare semplicemente il params[:commit]valore: riceverai params[:a_button]oa params[:b_button]seconda di quale è stato premuto.


2
Ancora non disaccoppia la vista dal controller.
slowpoison

1
Sì, se disaccoppiare significa evitare una logica nell'azione per indirizzare all'azione finale hai ragione, sono ancora accoppiati. Volevo solo dire che se usi l'attributo name in quella logica il tuo controller è indipendente da ciò che viene mostrato sul pulsante. Grazie, modificato
masciugo

4
Questo sembra essere migliore di quello accettato in situazioni i18n perché viene visualizzato "valore" e se stai visualizzando caratteri Unicode diventerebbe disordinato.
xji

2
Tuttavia i parametri non vengono lasciati passare. Sto usando simple_form gem. C'è qualche correlazione.
xji

1
Questo non disaccoppia la vista dal controller, ma almeno disaccoppia il testo visualizzato dal controller. molto meglio IMO.
Mic Fok

13

Soluzione simile a quella suggerita da @ vss123 senza l'utilizzo di gemme:

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

Si noti che evito di utilizzare value e utilizzo invece il nome di input poiché il valore del pulsante di invio è spesso internazionalizzato / tradotto. Inoltre, eviterei di usarlo troppo poiché ingombrerà rapidamente il file dei percorsi.


9

Abbiamo risolto utilizzando vincoli avanzati nei binari.

L'idea è di avere lo stesso percorso (e quindi la stessa rotta e azione denominate) ma con vincoli di instradamento verso azioni diverse.

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

CommitParamRouting è una semplice classe che ha un metodo matches? che restituisce true se il parametro commit corrisponde all'istanza data attr. valore.

Disponibile come gemma commit_param_matching .


3

Una vecchia domanda, ma poiché ho affrontato la stessa situazione, ho pensato di pubblicare la mia soluzione. Sto usando le costanti del controller per evitare di introdurre una discrepanza tra la logica del controller e il pulsante di visualizzazione.

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

E poi nella vista:

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

In questo modo il testo vive solo in un posto, come costante nel controller. Tuttavia, non ho ancora provato a capire come farlo.


Cosa intendi con "i18n"?
skrrgwasme

Questo era preferibile all'utilizzo di vincoli nel percorso? Grazie!
Timothy T.

@Scott: i18n significa "internazionalizzazione" - in pratica, come supporteresti più lingue. Non l'ho davvero esaminato, quindi non ho molta familiarità con come funziona o come implementarlo.
Draknor

@Angela - probabilmente no :) E in realtà, dopo il refactoring del mio codice, ho semplicemente creato più moduli, ciascuno con azioni diverse, piuttosto che un singolo modulo monolitico che conteneva un mucchio di moduli non correlati.
Draknor

1

Ho un numero variabile di pulsanti di invio sul mio modulo grazie a nested_form_fields, quindi usare solo il nome non era abbastanza per me. Ho finito per includere un campo di input nascosto nel modulo e utilizzare Javascript per popolarlo quando è stato premuto uno dei pulsanti di invio del modulo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.