Ruby on Rails: elimina più chiavi hash


148

Mi trovo spesso a scrivere questo:

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

La scia delle eliminazioni non sembra giusta e nemmeno:

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

C'è qualcosa di più semplice e più pulito?


Quando ho scritto che il secondo approccio non era corretto, intendevo dire che, data la ricchezza dell'API Hash, sospettavo che esistesse già un metodo o un linguaggio per questo e una patch scimmia non sarebbe stata necessaria. Forse no, comunque. Mille grazie a tutti coloro che hanno risposto!
Mark Westling,

3
Hash # tranne era esattamente quello che stavo cercando. Non ricordavo che si tratta di un'estensione core di Rails, quindi ero perplesso quando non riuscivo a trovarlo nell'API Hash.
Mark Westling,

1
Nota che rigorosamente la risposta è Hash#except!ma Hash#exceptè la strada da percorrere (non scherzare params!). Come regola generale, non scherzare con nessun oggetto sul posto a meno che non sia assolutamente necessario, gli effetti collaterali possono avere risultati inaspettati.
tokland

Risposte:


219

Immagino che tu non sia a conoscenza dell'Hash # tranne il metodo che ActiveSupport aggiunge a Hash.

Consentirebbe di semplificare il codice per:

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

Inoltre, non dovresti ricorrere alla scimmia, dal momento che il team di Rails l'ha fatto per te!


1
Ahhh, sapevo di averlo già visto prima, ma non riuscivo a ricordare dove! (Da qui la mia osservazione "questo non sembra giusto".) Grazie!
Mark Westling,

3
Uno di quei metodi meno documentati. Sono andato alla ricerca di qualcosa del genere mentre proponevo una risposta ma non l'ho vista.
Tadman,

1
Per qualche motivo tranne che non ha funzionato. Ma ha except!fatto. Rotaie 3.0
Viaggio

4
Rails 3.2 sugli attributi ActiveRecord, dovevi usare le stringhe per le chiavi? cioè i User.attributes.except("id", "created_at", "updated_at")simboli non funzionavano
house9

1
Aggiungendo a ciò che @ house9 ha menzionato, il attributesmetodo ActiveRecord restituisce un Hashcon le chiavi che lo sono String. Quindi dovresti usare i nomi delle chiavi di stringa in .except(). Comunque mi Hash.symbolize_keys@user.attributes.symbolize_keys.except(:password, :notes)symbolize_keys
aggiro

44

Durante l'utilizzo Hash#exceptgestisce il problema, tenere presente che introduce potenziali problemi di sicurezza . Una buona regola empirica per la gestione dei dati dai visitatori è quella di utilizzare un approccio whitelist. In questo caso, utilizzare Hash#sliceinvece.

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

1
Grazie per aver menzionato i problemi di sicurezza relativi al reindirizzamento.
David J.

12
Solo un avvertimento: ActiveSupport, non Ruby stesso, fornisce Hash # slice e #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.

1
Non sono riuscito a far funzionare il link di David James, ma questo sembra essere a posto: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers

metodo indefinito 'slice!' per{:b=>2, :c=>3}:Hash
Khurram Raza,

25

Sarei completamente contento del codice che hai originariamente pubblicato nella tua domanda.

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

senza modificare Hashquesta è la risposta migliore: +1:
Dan Bradbury

Ho usato questo metodo ma ho sostituito i parametri con il nome dell'hash e poi ha funzionato !! L'hash viene mutato.
Pablo,

13

Un altro modo di pronunciare la risposta di dmathieu potrebbe essere

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

8

Accendere una patch di scimmia?

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
Le patch di scimmie sono uno strumento di ultima istanza.
Bob Aman,

15
Le patch scimmia che sostituiscono le funzioni esistenti sono uno strumento di ultima istanza. Le patch Monkey che aggiungono nuove funzioni sono Ruby 101.
David Seiler,

4
Dovrebbe essere delete(k)invece didelete(key)
Vincent il

Per la manutenzione del codice l'implementazione del non distruttivo delete_keysdovrebbe essere semplicementedup.delete_keys!(*keys)
Phrogz,

@Phrogz Definire l'uno in termini dell'altro non è sempre una cattiva idea, ma è appena lasciato qui srotolato per chiarezza.
Tadman,

2

Non so cosa pensi sia sbagliato nella soluzione proposta. Suppongo che tu voglia un delete_allmetodo su Hash o qualcosa del genere? In tal caso, la risposta di Tadman fornisce la soluzione. Ma francamente, per una volta, penso che la tua soluzione sia estremamente facile da seguire. Se lo usi frequentemente, potresti volerlo avvolgere in un metodo di supporto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.