Bagaimana cara membuat beberapa tombol kirim untuk formulir yang sama di Rails?

98

Saya perlu memiliki beberapa tombol kirim.

Saya memiliki formulir yang membuat instance Contact_Call.

Satu tombol membuatnya seperti biasa.

Tombol lain membuatnya tetapi harus memiliki nilai yang berbeda: nilai atribut dari default, dan juga perlu menyetel atribut pada model yang berbeda, tetapi terkait yang digunakan dalam pengontrol.

Bagaimana aku melakukan itu? Saya tidak dapat mengubah rute, jadi apakah ada cara untuk mengirim variabel lain yang diambil oleh [: params]?

Dan jika saya melakukannya, apa yang harus saya lakukan di pengontrol, menyiapkan pernyataan kasus?

Timothy T.
sumber
kemungkinan duplikat Rails: Tombol kirim banyak dalam satu Formulir
Joshua Pinter
3
Yang ini lebih tua dan memiliki lebih banyak suara. Jika ada yang di atas harus ditutup sebagai duplikat dari ini ...
Taryn East

Jawaban:

129

Anda dapat membuat beberapa tombol kirim dan memberikan nilai yang berbeda untuk masing-masing:

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

Ini akan menghasilkan:

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

Di dalam pengontrol Anda, nilai tombol yang dikirimkan akan diidentifikasi oleh parameter commit. Periksa nilai untuk melakukan pemrosesan yang diperlukan:

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

Namun, ingatlah bahwa ini akan menghubungkan pandangan Anda dengan pengontrol yang mungkin tidak terlalu diinginkan.

Anurag
sumber
1
Sekarang itu sesuatu yang baru. Terima kasih @Anurag!
Shripad Krishna
1
jadi hanya menempatkan 'A' secara otomatis membuat nama parameter = 'komit'?
Timothy T.
apakah ada cara seperti yang Anda katakan untuk tidak memasangkan secara erat view ke controller? misalnya, untuk tombol kirim untuk mengubah URL? Ini tampaknya bahwa ini tidak selalu buruk karena pengiriman formulir variabel yang dapat mengubah perilaku hte controller, e ven jika input pengguna, yang pemilihan tombol ini?
Timothy T.
1
Anda tidak dapat mengubah atribut tindakan formulir tanpa peretasan js yang berantakan.
Ben Orozco
Mengubah atribut tindakan bentuk dengan cepat adalah solusi yang lebih rapuh. Menggunakan atribut komit kurang dari itu. Sebagai alternatif, Anda bisa membungkus tombol kirim kedua di dalam formulir berbeda dan meneruskan parameter yang perlu diubah ke tindakan yang sama. Namun tidak jauh berbeda dengan mengandalkan nilai dari 2 tombol submit. Tanpa mengetahui lebih lanjut bagaimana Anda mengatur hal ini, solusi terbaik sejauh ini adalah dengan 2 tombol kirim.
Anurag
75

Ada juga pendekatan lain, menggunakan atribut formaction pada tombol kirim:

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

Kode tetap bersih, karena tombol buat standar tidak memerlukan perubahan apa pun, Anda hanya memasukkan jalur perutean untuk tombol khusus:

formaction:
URI program yang memproses informasi yang dikirimkan oleh elemen input, jika berupa tombol kirim atau gambar. Jika ditentukan, tindakan ini akan mengganti atribut tindakan dari pemilik bentuk elemen . Sumber: MDN

patpir
sumber
8
Saya menyadari pertanyaan itu sudah lama, tetapi saya menyarankan pembaca bahwa solusi ringkas ini layak mendapat pertimbangan yang lebih baik.
Jerome
2
Saya berharap saya menemukan jawaban ini saat pertama kali saya memiliki pertanyaan yang sama. Saya senang saya memutuskan untuk melihat lebih dalam kali ini. Solusi bagus.
rockusbacchus
1
Saya sangat menyukai solusi ini. Namun, saya harus menambahkan bidang tersembunyi dengan token CSRF meskipun saya sudah menggunakan bantuan formulir atau Rails tidak akan menerima token tersebut. Saya tidak dapat menemukan solusi yang lebih baik dan saya masih tidak yakin mengapa hal ini terjadi atau hanya menambahkan token untuk memperbaikinya.
irruputuncu
Saya pikir ini adalah solusi yang lebih baik karena menghormati prinsip tanggung jawab tunggal dan menjaga hal-hal tetap jelas setiap tombol melakukan tindakannya sendiri menjaga logika dalam pengontrol tetap sederhana.
Khalil Gharbaoui
29

Sebagai alternatif, Anda dapat mengenali tombol mana yang ditekan untuk mengubah nama atributnya.

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

Ini sedikit tidak nyaman karena Anda harus memeriksa keberadaan kunci params daripada hanya memeriksa params[:commit]nilai: Anda akan menerima params[:a_button]atau params[:b_button]bergantung pada yang mana yang ditekan.

masciugo
sumber
2
Masih tidak memisahkan tampilan dari pengontrol.
slowpoison
1
Ya, jika decouple berarti menghindari beberapa logika dalam tindakan tersebut untuk mengarahkan Anda ke tindakan terakhir yang benar, keduanya masih digabungkan. Saya hanya bermaksud bahwa jika Anda menggunakan atribut name dalam logika itu, pengontrol Anda tidak tergantung dari apa yang ditampilkan di tombol. Terima kasih, diedit
masciugo
4
Yang ini tampaknya lebih baik daripada yang diterima dalam situasi i18n karena "nilai" ditampilkan dan jika Anda menampilkan karakter Unicode, itu akan menjadi berantakan.
xji
2
Namun parameter tidak dibiarkan masuk. Saya menggunakan permata simple_form. Apakah ada korelasi.
xji
1
Ini tidak memisahkan tampilan dari pengontrol, tetapi setidaknya ini memisahkan teks yang ditampilkan dari pengontrol. IMO jauh lebih baik.
Mic Fok
13

Solusi serupa dengan yang disarankan oleh @ vss123 tanpa menggunakan permata apa pun:

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

Perhatikan bahwa saya menghindari menggunakan nilai dan menggunakan nama input sebagai gantinya karena nilai tombol kirim sering diinternasionalkan / diterjemahkan. Juga, saya akan menghindari penggunaan ini terlalu banyak karena akan dengan cepat mengacaukan file rute Anda.

Tadas Sasnauskas
sumber
9

Kami menyelesaikannya menggunakan kendala lanjutan di rel.

Idenya adalah memiliki jalur yang sama (dan karenanya dinamai rute & tindakan yang sama) tetapi dengan batasan perutean ke tindakan yang berbeda.

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

CommitParamRoutingadalah kelas sederhana yang memiliki metode matches?yang mengembalikan nilai true jika parameter komit cocok dengan atribut contoh yang diberikan. nilai.

Ini tersedia sebagai permata commit_param_matching .

siliconsenthil.dll
sumber
3

Pertanyaan lama, tetapi karena saya telah menghadapi situasi yang sama, saya pikir saya akan memposting solusi saya. Saya menggunakan konstanta pengontrol untuk menghindari perbedaan antara logika pengontrol dan tombol tampilan.

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

Dan kemudian dalam tampilan:

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

Dengan cara ini teks hanya berada di satu tempat - sebagai konstanta di pengontrol. Namun, saya belum mencoba mencari cara untuk melakukan ini.

Draknor
sumber
Apa yang Anda maksud dengan "i18n"?
skrrgwasme
Apakah ini lebih disukai daripada menggunakan batasan dalam rute? Terima kasih!
Timothy T.
@Scott: i18n berarti 'internasionalisasi' - pada dasarnya, bagaimana Anda mendukung banyak bahasa. Saya belum benar-benar memeriksanya, jadi saya tidak begitu paham dengan cara kerjanya atau cara menerapkannya.
Draknor
@Angela - mungkin tidak :) Dan sebenarnya, setelah refactoring kode saya, saya hanya membuat beberapa formulir, masing-masing dengan tindakan yang berbeda, daripada satu formulir monolitik yang berisi sekumpulan formulir yang tidak terkait.
Draknor
1

Saya memiliki sejumlah variabel tombol kirim pada formulir saya berkat nested_form_fields, jadi hanya menggunakan nama saja tidak cukup bagi saya. Saya akhirnya memasukkan bidang input tersembunyi dalam formulir dan menggunakan Javascript untuk mengisinya ketika salah satu tombol kirim formulir ditekan.

Shawn Walton
sumber