Rails'de aynı form için birden çok gönderme düğmesi nasıl oluşturabilirim?


98

Birden çok gönderme düğmesine ihtiyacım var.

Contact_Call örneğini oluşturan bir formum var.

Bir düğme onu normal bir şekilde oluşturur.

Diğer düğme onu oluşturur ancak varsayılandan farklı bir: öznitelik değerine sahip olması gerekir ve aynı zamanda denetleyicide kullanılan farklı, ancak ilgili bir modelde özniteliği ayarlaması gerekir.

Bunu nasıl yaparım? Rotayı değiştiremiyorum, dolayısıyla [: params] tarafından alınan farklı bir değişken göndermenin bir yolu var mı?

Ve sonra yaparsam, denetleyicide ne yapmalıyım, bir vaka ifadesi oluşturmalıyım?



3
Bu daha eski ve daha fazla oyu var. Yukarıdakilerin bir kopyası olarak kapatılması gerekirse ...
Taryn East

Yanıtlar:


128

Birden çok gönderme düğmesi oluşturabilir ve her birine farklı bir değer verebilirsiniz:

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

Bu çıktı:

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

Denetleyicinizin içinde, gönderilen düğmenin değeri parametre ile tanımlanacaktır commit. Gerekli işlemi yapmak için değeri kontrol edin:

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

Bununla birlikte, bunun, görüşünüzü denetleyiciye sıkı bir şekilde bağladığını unutmayın, bu çok da istenmeyebilir.


1
Şimdi bu yeni bir şey. Teşekkürler @Anurag!
Shripad Krishna

1
yani sadece 'A' otomatik olarak name = 'commit' parametresini oluştursun.
Timothy T.

Görüntüyü denetleyiciye sıkıca bağlamamanın bir yolu var mı? örneğin, gönder düğmelerinin URL'yi değiştirmesi için? O görünüyor o kullanıcı girişi varsa Hte kontrolörü davranışını değiştirecek bir form gönderdiğinde değişkenler, e düğmesinin seçimi olan ven çünkü bu mutlaka kötü olmadığını?
Timothy T.

1
Dağınık bir js hack olmadan bir form eylemi özelliğini değiştiremezsiniz.
Ben Orozco

Hareket halindeyken form eylemi niteliğini değiştirmek daha kırılgan bir çözümdür. Commit özniteliğini kullanmak daha azdır. Alternatif olarak, ikinci gönder düğmesini farklı bir formun içine sarabilir ve aynı eyleme değiştirilmesi gereken bir parametreyi iletebilirsiniz. Ancak, 2 gönder düğmesinin değerlerine güvenmekten çok da farklı değildir. Bu şeyi nasıl kurduğunuzu daha fazla bilmeden, şimdiye kadarki en iyi çözüm 2 gönder düğmesi olacaktır.
Anurag

77

Gönder düğmesindeki formaction özelliğini kullanan başka bir yaklaşım daha vardır:

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

Standart oluştur düğmesinin herhangi bir değişikliğe ihtiyacı olmadığı için kod temiz kalır, yalnızca özel düğme için bir yönlendirme yolu eklersiniz:

formaction:
Bir gönder düğmesi veya resmi ise, giriş öğesi tarafından gönderilen bilgileri işleyen bir programın URI'sı. Belirtilirse, öğenin form sahibinin eylem özniteliğini geçersiz kılar . Kaynak: MDN



8
Sorunun eski olduğunun farkındayım, ancak okuyuculara bu kısa çözümün daha iyi değerlendirilmeyi hak ettiğini tavsiye ediyorum.
Jerome

2
Keşke aynı soruyu ilk kez sorduğumda bu cevabı bulsaydım. Bu sefer biraz daha derinlemesine bakmaya karar verdiğim için memnunum. Harika çözüm.
rockusbacchus

1
Bu çözümü gerçekten beğendim. Ancak, zaten form yardımcıları kullanıyor olsam da CSRF belirteci ile gizli bir alan eklemem gerekiyordu veya Rails jetonu kabul etmiyordu. Daha iyi bir geçici çözüm bulamadım ve bunun tam olarak neden gerçekleştiğinden veya yalnızca belirteci tekrar eklemenin sorunu düzelttiğinden hala emin değilim.
irruputuncu

Bunun daha iyi bir çözüm olduğunu düşünüyorum çünkü tek sorumluluk ilkelerine saygı gösteriyor ve her düğmenin kontrolörlerde mantığı basit tutarak kendi eylemini gerçekleştirmesini sağlıyor.
Halil Gharbaoui

29

Alternatif olarak, öznitelik adını değiştirerek hangi düğmeye basıldığını anlayabilirsiniz.

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

Biraz rahatsız edici çünkü basitçe params[:commit]değeri kontrol etmek yerine params tuşlarının varlığını kontrol etmeniz gerekiyor: alacaksınız params[:a_button]veya params[:b_button]hangisine basıldığına bağlı olarak.


2
Yine de denetleyiciden görünümü ayırmıyor.
slowpoison

1
Evet, eğer ayırma, haklı olduğunuz son eyleme yönlendirmek için eylemde bazı mantıklardan kaçınmak anlamına geliyorsa, bunlar hala birleşmiş durumdadır. Demek istediğim, bu mantıkta name özniteliğini kullanırsanız, denetleyiciniz düğmede gösterilenden bağımsızdır. Teşekkürler, düzenlendi
masciugo

4
Bu, i18n durumlarında kabul edilenden daha iyi görünüyor çünkü "değer" görüntüleniyor ve Unicode karakterleri görüntülüyorsanız, karışıklık yaratacaktır.
xji

2
Ancak parametrelere izin verilmiyor. Simple_form gem kullanıyorum. Herhangi bir ilişki var mı?
xji

1
Bu, görünümü denetleyiciden ayırmaz, ancak en azından denetleyiciden görüntülenen metni ayırır. çok daha iyi IMO.
Mic Fok

13

@ Vss123 tarafından herhangi bir mücevher kullanmadan önerilen bir çözüm:

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

Gönder düğmesi değeri genellikle uluslararası hale getirildiği / çevrildiği için değer kullanmaktan kaçındığıma ve bunun yerine giriş adı kullandığıma dikkat edin. Ayrıca, rota dosyanızı hızla karıştıracağından bunu çok fazla kullanmaktan kaçınırım.


9

Raylarda gelişmiş kısıtlamalar kullanarak çözdük .

Buradaki fikir, aynı yola (ve dolayısıyla aynı adlandırılmış rota ve eyleme) sahip olmaktır, ancak farklı eylemlere yönlendiren kısıtlamalarla.

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

CommitParamRoutingmatches?commit parametresi verilen öznitelik ile eşleşirse true döndüren bir metoda sahip basit bir sınıftır . değer.

Bu, bir gem commit_param_matching olarak mevcuttur .


3

Eski bir soru, ama aynı durumla uğraştığım için çözümümü göndereceğimi düşündüm. Denetleyici mantığı ile görünüm düğmesi arasında bir tutarsızlık olmasını önlemek için denetleyici sabitlerini kullanıyorum.

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

Ve sonra görünümde:

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

Bu şekilde metin yalnızca tek bir yerde bulunur - kontrolörde sabit olarak. Ancak henüz bunu nasıl yapacağımı anlamaya çalışmadım.


"İ18n" ile ne demek istiyorsun?
skrrgwasme

Bu, rotada kısıtlamalar kullanmak yerine tercih edildi mi? Teşekkürler!
Timothy T.

@Scott: i18n 'uluslararasılaşma' anlamına gelir - temelde, birden fazla dili nasıl desteklersiniz. Gerçekten araştırmadım, bu yüzden nasıl çalıştığını veya nasıl uygulanacağını pek bilmiyorum.
Draknor'da

@Angela - muhtemelen değil :) Ve aslında, kodumu yeniden düzenledikten sonra, bir grup ilgisiz form içeren tek bir monolitik form yerine, her biri farklı eylemlere sahip birden fazla form oluşturdum.
Draknor'da

1

Nested_form_fields sayesinde formumda değişken sayıda gönderme butonlarım var, bu yüzden sadece adı kullanmak benim için yeterli değildi. Formda gizli bir giriş alanı ekledim ve form gönderme düğmelerinden birine basıldığında Javascript'i doldurmak için kullandım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.