Ruby on Rails: ลบคีย์แฮชหลายตัว


148

ฉันมักจะพบว่าตัวเองเขียนสิ่งนี้:

params.delete(:controller)  
params.delete(:action)  
params.delete(:other_key)  
redirect_to my_path(params)  

เส้นทางแห่งการลบไม่รู้สึกถูกต้องและไม่เป็นเช่นนั้น:

[:controller, :action, :other_key].each do |k|
  params.delete(k)
end

มีอะไรที่ง่ายและสะอาดกว่านี้ไหม?


เมื่อฉันเขียนว่าวิธีที่สองรู้สึกไม่ถูกต้องฉันหมายความว่าด้วยความสมบูรณ์ของ Hash API ฉันสงสัยว่ามีวิธีหรือสำนวนออกมาแล้วสำหรับเรื่องนี้และไม่จำเป็นต้องใช้แผ่นปะลิง อาจจะไม่ใช่ ขอบคุณมากสำหรับทุกคนที่ตอบ!
Mark Westling

3
# แฮชยกเว้นเป็นสิ่งที่ฉันกำลังมองหา ฉันจำไม่ได้ว่าเป็นส่วนขยายหลักของ Rails ดังนั้นฉันจึงสับสนเมื่อไม่สามารถหาได้ใน Hash API
Mark Westling

1
โปรดทราบว่าคำตอบอย่างเคร่งครัดคือHash#except!แต่Hash#exceptเป็นวิธีที่จะไป (อย่ายุ่งกับparams!) ในฐานะที่เป็นกฎง่ายๆอย่ายุ่งกับวัตถุใด ๆ ในสถานที่นอกเสียจากว่าจำเป็นอย่างยิ่งผลข้างเคียงอาจมีผลที่ไม่คาดคิด
tokland

คำตอบ:


219

ฉันคาดเดาว่าคุณไม่ทราบแฮช # ยกเว้นวิธีที่ ActiveSupport เพิ่มลงในแฮช

มันจะช่วยให้รหัสของคุณง่ายต่อการ:

redirect_to my_path(params.except(:controller, :action, :other_key))

นอกจากนี้คุณไม่ต้องติดแผ่นแป็นลิงเนื่องจากทีม Rails ทำเพื่อคุณ!


1
Ahhh ฉันรู้ว่าฉันเคยเห็นสิ่งนี้มาก่อน แต่ฉันจำไม่ได้ว่าอยู่ที่ไหน! (ดังนั้นคำพูด "นี้ไม่รู้สึกถูกต้อง" ของฉัน) ขอบคุณ!
Mark Westling

3
หนึ่งในวิธีการที่มีเอกสารน้อยกว่านั้น ฉันไปหาบางอย่างเช่นนี้ขณะเสนอคำตอบ แต่ไม่เห็น
tadman

1
ด้วยเหตุผลบางอย่างยกเว้นไม่ทำงาน แต่except!ทำ Rails 3.0
Trip

4
Rails 3.2 บนแอ็ตทริบิวต์ ActiveRecord จำเป็นต้องใช้สตริงสำหรับคีย์หรือไม่? เช่นUser.attributes.except("id", "created_at", "updated_at")สัญลักษณ์ไม่ทำงาน
house9

1
เพิ่มสิ่งที่ @ house9 กล่าว ActiveRecord attributesวิธีการส่งกลับด้วยปุ่มที่มีHash ดังนั้นแล้วคุณจะต้องใช้ชื่อคีย์สตริงในString .except()อย่างไรก็ตามฉันได้รับสิ่งนี้โดยใช้Hash.symbolize_keysla @user.attributes.symbolize_keys.except(:password, :notes)- การใช้symbolize_keysทำให้มันทำงานอย่างที่คาดหวัง
FireDragon

44

ในขณะที่ใช้Hash#exceptมือจับปัญหาของคุณได้ทราบว่ามันแนะนำปัญหาด้านความปลอดภัยที่อาจเกิดขึ้น กฎง่ายๆสำหรับการจัดการข้อมูลใด ๆ จากผู้เข้าชมคือการใช้วิธีการที่อนุญาต ในกรณีนี้ให้ใช้Hash#sliceแทน

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)

1
ขอขอบคุณที่กล่าวถึงปัญหาด้านความปลอดภัยโดยรอบการเปลี่ยนเส้นทาง
David J.

12
แค่หัวขึ้น: ActiveSupport ไม่ใช่ตัว Ruby ให้ Hash # slice และ #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.

1
ฉันไม่สามารถใช้ลิงค์ของ David James ได้ แต่อันนี้ดูเหมือนจะโอเค: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers

วิธีการที่ไม่ได้ระบุ 'slice!' for{:b=>2, :c=>3}:Hash
Khurram Raza

25

ฉันมีความสุขอย่างสมบูรณ์กับรหัสที่คุณโพสต์ไว้ในคำถามของคุณ

[:controller, :action, :other_key].each { |k| params.delete(k) }

โดยไม่ต้องแก้ไขHashนี่เป็นคำตอบที่ดีที่สุด: +1:
Dan Bradbury

ฉันใช้วิธีนี้ แต่แทนที่ params ด้วยชื่อของแฮชแล้วมันใช้งานได้ !! แฮชจะกลายพันธุ์
Pablo

13

อีกวิธีหนึ่งในการตอบวลีของ dmathieu อาจเป็นได้

params.delete_if { |k,v| [:controller, :action, :other_key].include? k }

8

จุดชนวนเพลิงลิง?

class Hash
  def delete_keys!(*keys)
    keys.flatten.each do |k|
      delete(k)
    end

    self
  end

  def delete_keys(*keys)
    _dup = dup
    keys.flatten.each do |k|
      _dup.delete(k)
    end

    _dup
  end
end

5
แพทช์ลิงเป็นเครื่องมือสุดท้าย
Bob Aman

15
แพทช์ลิงที่แทนที่ฟังก์ชั่นที่มีอยู่เป็นเครื่องมือสุดท้าย แพทช์ลิงที่เพิ่มฟังก์ชั่นใหม่คือ Ruby 101
David Seiler

4
ควรdelete(k)แทนdelete(key)
Vincent

สำหรับการบำรุงรักษาโค้ดการใช้งานแบบไม่ทำลายdelete_keysควรจะเป็นเพียงdup.delete_keys!(*keys)
Phrogz

@Phrogz การกำหนดหนึ่งในแง่ของอื่น ๆ ไม่ได้เป็นความคิดที่ดีเสมอ แต่มันเพิ่งออกจากที่นี่เพื่อคลี่คลายความชัดเจน
tadman

2

ฉันไม่รู้ว่าสิ่งที่คุณคิดว่าผิดกับโซลูชันที่คุณเสนอ ฉันคิดว่าคุณต้องการdelete_allวิธีการในแฮชหรืออะไร? ถ้าเป็นเช่นนั้นคำตอบของ tadmanจะให้คำตอบ แต่ตรงไปตรงมาฉันคิดว่าทางออกของคุณนั้นง่ายมาก หากคุณใช้งานบ่อยครั้งคุณอาจจำเป็นต้องปิดมันด้วยวิธีการช่วยเหลือ

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