Ruby on Rails: Hapus beberapa kunci hash

148

Saya sering menemukan diri saya menulis ini:

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

Jejak penghapusan tidak terasa benar dan tidak juga:

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

Adakah yang lebih sederhana dan lebih bersih?

Mark Westling
sumber
Ketika saya menulis bahwa pendekatan kedua tidak terasa benar, saya maksudkan bahwa mengingat kekayaan API Hash, saya menduga bahwa ada beberapa metode atau idiom yang sudah ada di luar sana untuk ini dan patch monyet tidak diperlukan. Mungkin tidak. Terima kasih banyak untuk semua yang menjawab!
Mark Westling
3
Hash # kecuali persis apa yang saya cari. Saya tidak ingat bahwa itu adalah ekstensi inti Rails jadi saya bingung ketika saya tidak dapat menemukannya di API Hash.
Mark Westling
1
Perhatikan bahwa ketat jawabannya adalah Hash#except!tetapi Hash#exceptadalah cara untuk pergi (jangan main-main dengan params!). Sebagai aturan praktis, jangan main-main dengan objek apa pun di tempat kecuali benar-benar diperlukan, efek samping mungkin memiliki hasil yang tidak terduga.
tokland

Jawaban:

219

Saya kira Anda tidak mengetahui Hash # kecuali metode ActiveSupport menambah Hash.

Ini akan memungkinkan kode Anda disederhanakan menjadi:

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

Juga, Anda tidak perlu menambal monyet, karena tim Rails melakukannya untuk Anda!

Ben Crouse
sumber
1
Ahhh, aku tahu aku pernah melihat ini sebelumnya tapi aku tidak ingat di mana! (Oleh karena itu komentar "ini rasanya tidak benar".) Terima kasih!
Mark Westling
3
Salah satu metode yang kurang terdokumentasi. Saya pergi mencari sesuatu seperti ini sambil mengusulkan jawaban tetapi tidak melihatnya.
tadman
1
Untuk beberapa alasan kecuali tidak berhasil. Tapi itu except!benar. Rails 3.0
Trip
4
Rails 3.2 pada atribut ActiveRecord, harus menggunakan string untuk kunci? yaitu User.attributes.except("id", "created_at", "updated_at")simbol tidak bekerja
house9
1
Menambahkan ke apa yang disebutkan @ house9, attributesmetode ActiveRecord mengembalikan Hashkunci dengan String. Jadi, Anda harus menggunakan nama kunci string di .except(). Namun saya menyiasati ini menggunakan Hash.symbolize_keysa @user.attributes.symbolize_keys.except(:password, :notes)- menggunakan symbolize_keysmembuatnya berfungsi seperti yang diharapkan
FireDragon
44

Saat menggunakan Hash#exceptmenangani masalah Anda, ketahuilah bahwa masalah tersebut berpotensi menimbulkan masalah keamanan . Aturan praktis yang baik untuk menangani data dari pengunjung adalah menggunakan pendekatan daftar putih. Dalam hal ini, gunakan Hash#slicesaja.

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)
jsa
sumber
1
Terima kasih telah menyebutkan masalah keamanan seputar pengalihan.
David J.
12
Hanya kepala: ActiveSupport, bukan Ruby itu sendiri, menyediakan Hash # slice dan #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.
1
Saya tidak bisa mendapatkan tautan David James untuk bekerja tetapi yang ini tampaknya ok: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers
metode 'slice!' untuk{:b=>2, :c=>3}:Hash
Khurram Raza
25

Saya akan sangat senang dengan kode yang semula Anda posting di pertanyaan Anda.

[:controller, :action, :other_key].each { |k| params.delete(k) }
Bob Aman
sumber
tanpa memodifikasi Hashini adalah jawaban terbaik: +1:
Dan Bradbury
Saya telah menggunakan metode ini tetapi mengganti params dengan nama hash dan kemudian berhasil !! Hash akan dimutasi.
Pablo
13

Cara lain untuk frase jawaban dmathieu mungkin

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

Jalankan patch monyet?

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
anak laki-laki
sumber
5
Patch monyet adalah alat pilihan terakhir.
Bob Aman
15
Patch monyet yang menggantikan fungsi yang ada adalah alat pilihan terakhir. Patch monyet yang menambahkan fungsi baru adalah Ruby 101.
David Seiler
4
Seharusnya delete(k)bukandelete(key)
Vincent
Untuk pemeliharaan kode, implementasi non-destruktif delete_keysharus sederhanadup.delete_keys!(*keys)
Phrogz
@ Phyz Mendefinisikan satu dalam hal yang lain tidak selalu merupakan ide yang buruk, tetapi hanya dibiarkan di sini terbuka untuk kejelasan.
tadman
2

Saya tidak tahu apa yang Anda pikir salah dengan solusi yang Anda usulkan. Saya kira Anda ingin delete_allmetode pada Hash atau sesuatu? Jika demikian, jawaban tadman memberikan solusi. Tapi terus terang, untuk sekali saja, saya pikir solusi Anda sangat mudah diikuti. Jika Anda sering menggunakan ini, Anda mungkin ingin membungkusnya dengan metode pembantu.

pesto
sumber