ฉันจะสร้างปุ่มส่งหลายปุ่มสำหรับแบบฟอร์มเดียวกันใน Rails ได้อย่างไร


98

ฉันต้องมีปุ่มส่งหลายปุ่ม

ฉันมีแบบฟอร์มที่สร้างอินสแตนซ์ของ Contact_Call

ปุ่มเดียวสร้างได้ตามปกติ

ปุ่มอื่น ๆ จะสร้างมันขึ้นมา แต่ต้องมีค่า: attribute ที่แตกต่างจากค่าเริ่มต้นและยังต้องตั้งค่าแอตทริบิวต์ในรูปแบบอื่น แต่เกี่ยวข้องกันที่ใช้ในคอนโทรลเลอร์

ฉันจะทำอย่างไร? ฉันไม่สามารถเปลี่ยนเส้นทางได้มีวิธีส่งตัวแปรอื่นที่ [: params] มารับหรือไม่

และถ้าฉันทำเช่นนั้นฉันจะทำอย่างไรในคอนโทรลเลอร์ตั้งค่าคำสั่งเคส



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!
Shripad Krishna

1
ดังนั้นเพียงแค่ใส่ 'A' โดยอัตโนมัติสร้างชื่อพารามิเตอร์ = 'กระทำ'?
Timothy T.

มีวิธีดังที่คุณบอกว่าอย่าจับคู่มุมมองกับคอนโทรลเลอร์ให้แน่นหรือไม่? ตัวอย่างเช่นสำหรับปุ่มส่งเพื่อเปลี่ยน URL? มันดูเหมือนว่าเรื่องนี้ไม่จำเป็นต้องดีเพราะตัวแปรส่งแบบฟอร์มที่สามารถเปลี่ยนพฤติกรรมของตัวควบคุมจังหวัดอุบลราชธานีที่อีเวนถ้ามันเข้าของผู้ใช้ซึ่งการเลือกปุ่มคืออะไร?
Timothy T.

1
คุณไม่สามารถเปลี่ยนแอตทริบิวต์ form action ได้โดยไม่ต้องใช้ js hack ที่ยุ่งเหยิง
Ben Orozco

การเปลี่ยนแอตทริบิวต์ form action ได้ทันทีเป็นวิธีแก้ปัญหาที่เปราะบางกว่า การใช้แอตทริบิวต์การกระทำนั้นน้อยกว่า คุณสามารถเป็นอีกทางเลือกหนึ่งที่จะรวมปุ่มส่งที่สองไว้ในรูปแบบอื่นและส่งผ่านพารามิเตอร์ที่ต้องเปลี่ยนเป็นการกระทำเดียวกัน แต่ก็ไม่แตกต่างกันมากไปกว่าการอาศัยค่าของปุ่มส่ง 2 ปุ่ม หากไม่ทราบเพิ่มเติมว่าคุณตั้งค่าสิ่งนี้อย่างไรทางออกที่ดีที่สุดคือปุ่มส่ง 2 ปุ่ม
Anurag

79

นอกจากนี้ยังมีอีกวิธีหนึ่งโดยใช้แอตทริบิวต์ formaction บนปุ่มส่ง:

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

รหัสยังคงสะอาดอยู่เนื่องจากปุ่มสร้างมาตรฐานไม่ต้องการการเปลี่ยนแปลงใด ๆ คุณเพียงแทรกเส้นทางการกำหนดเส้นทางสำหรับปุ่มพิเศษเท่านั้น:

formaction:
URI ของโปรแกรมที่ประมวลผลข้อมูลที่ส่งโดยองค์ประกอบอินพุตหากเป็นปุ่มส่งหรือรูปภาพ หากระบุว่ามันจะแทนที่แอตทริบิวต์การกระทำของเจ้าของรูปแบบขององค์ประกอบ ที่มา: MDN


3
รองรับในทุกเบราว์เซอร์w3schools.com/tags/att_button_formaction.asp w3schools.com/tags/att_input_formaction.asp
Sumit Garg

8
ฉันรู้ว่าคำถามนี้เก่า แต่ฉันแนะนำให้ผู้อ่านทราบว่าวิธีแก้ปัญหาที่กระชับนี้ควรได้รับการพิจารณาที่ดีกว่า
เจอโรม

2
ฉันหวังว่าฉันจะพบคำตอบนี้ในครั้งแรกที่มีคำถามเดียวกันนี้ ฉันดีใจที่ตัดสินใจมองลึกลงไปในครั้งนี้ ทางออกที่ดี
rockusbacchus

1
ฉันชอบโซลูชันนี้มาก อย่างไรก็ตามฉันต้องเพิ่มฟิลด์ที่ซ่อนด้วยโทเค็น CSRF แม้ว่าฉันจะใช้ตัวช่วยแบบฟอร์มอยู่แล้วหรือ Rails จะไม่ยอมรับโทเค็น ฉันไม่พบวิธีแก้ปัญหาที่ดีกว่านี้และฉันยังไม่แน่ใจว่าเหตุใดสิ่งนี้จึงเกิดขึ้นหรือเพียงแค่เพิ่มโทเค็นอีกครั้งก็สามารถแก้ไขได้
irruputuncu

ฉันคิดว่านี่เป็นทางออกที่ดีกว่าเพราะเคารพหลักการความรับผิดชอบเดียวและทำให้ทุกอย่างชัดเจนแต่ละปุ่มดำเนินการของตัวเองทำให้ตรรกะในตัวควบคุมง่ายขึ้น
Khalil Gharbaoui

30

คุณสามารถรับรู้ได้ว่าปุ่มใดถูกกดเพื่อเปลี่ยนชื่อแอตทริบิวต์

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

รู้สึกอึดอัดเล็กน้อยเพราะคุณต้องตรวจสอบการมีคีย์ params แทนการตรวจสอบparams[:commit]ค่า: คุณจะได้รับparams[:a_button]หรือparams[:b_button]ขึ้นอยู่กับว่าปุ่มใดถูกกด


2
ยังไม่แยกมุมมองจากคอนโทรลเลอร์
slowpoison

1
ใช่ถ้า decouple หมายถึงการหลีกเลี่ยงตรรกะบางอย่างในการดำเนินการเพื่อกำหนดเส้นทางไปสู่การดำเนินการขั้นสุดท้ายที่คุณคิดถูกมันจะยังคงอยู่คู่กัน ฉันแค่หมายความว่าถ้าคุณใช้แอตทริบิวต์ชื่อในตรรกะนั้นคอนโทรลเลอร์ของคุณจะไม่ขึ้นอยู่กับสิ่งที่แสดงบนปุ่ม ขอบคุณแก้ไข
masciugo

4
อันนี้ดูเหมือนจะดีกว่าที่ยอมรับในสถานการณ์ i18n เนื่องจากมีการแสดง "value" และหากคุณแสดงอักขระ Unicode มันจะยุ่งเหยิง
xji

2
อย่างไรก็ตามพารามิเตอร์จะไม่ถูกปล่อยผ่าน ฉันใช้อัญมณีแบบ simple_form มีความสัมพันธ์กันหรือไม่
xji

1
สิ่งนี้ไม่ได้แยกมุมมองออกจากคอนโทรลเลอร์ แต่อย่างน้อยมันก็แยกข้อความที่แสดงจากคอนโทรลเลอร์ IMO ที่ดีกว่ามาก
Mic Fok

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

CommitParamRoutingเป็นคลาสง่ายๆที่มีเมธอดmatches?ที่ส่งกลับค่า true ถ้าพารามิเตอร์การกระทำตรงกับอินสแตนซ์ attr ที่กำหนด มูลค่า.

นี้สามารถใช้ได้เป็นอัญมณี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 %>

วิธีนี้ข้อความจะอยู่ในที่เดียวเท่านั้น - เป็นค่าคงที่ในคอนโทรลเลอร์ ฉันยังไม่ได้พยายามหาวิธี i18n นี้อย่างไรก็ตาม


"i18n" หมายถึงอะไร
skrrgwasme

วิธีนี้ดีกว่าที่จะใช้ข้อ จำกัด ในเส้นทางหรือไม่? ขอบคุณ!
Timothy T.

@Scott: i18n หมายถึง 'ความเป็นสากล' - โดยพื้นฐานแล้วคุณจะรองรับหลายภาษาได้อย่างไร ฉันไม่ได้ตรวจสอบอย่างแท้จริงดังนั้นฉันจึงไม่ค่อยคุ้นเคยกับวิธีการทำงานหรือวิธีการนำไปใช้
Draknor

@Angela - อาจจะไม่ใช่ :) และจริงๆแล้วหลังจากปรับโครงสร้างโค้ดของฉันใหม่ฉันก็สร้างหลายรูปแบบโดยแต่ละรูปแบบมีการกระทำที่แตกต่างกันแทนที่จะเป็นรูปแบบเสาหินเดียวที่มีรูปแบบที่ไม่เกี่ยวข้องกันมากมาย
Draknor

1

ฉันมีปุ่มส่งหลายปุ่มในแบบฟอร์มของฉันซึ่งต้องขอบคุณ nested_form_fields ดังนั้นแค่ใช้ชื่อก็ไม่เพียงพอสำหรับฉัน ฉันลงเอยด้วยการรวมช่องป้อนข้อมูลที่ซ่อนอยู่ในแบบฟอร์มและใช้ Javascript เพื่อเติมข้อมูลเมื่อกดปุ่มส่งแบบฟอร์มปุ่มใดปุ่มหนึ่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.