2009-10-13 51 views
126

a menudo me encuentro escribiendo esto:Ruby on Rails: Eliminar varias claves hash

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

La estela de eliminaciones no se siente bien y tampoco lo hace:

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

¿Hay algo más simple y ¿limpiador?

+0

Cuando escribí que el segundo enfoque no se sentía bien, me refería a que, dada la riqueza de la API de Hash, sospechaba que había algún método o idioma ya que hay para esto y un parche mono wouldn' ser necesario Quizás no, sin embargo. Muchas gracias a todos los que respondieron! –

+3

Hash # excepto que era exactamente lo que estaba buscando. No recuerdo que es una extensión principal de Rails, así que me quedé desconcertado cuando no pude encontrarla en la API de Hash. –

+1

Tenga en cuenta que estrictamente la respuesta es 'Hash # ¡excepto!' Pero 'Hash # except' es el camino a seguir (¡no se meta con' params'!). Como regla general, no te metas con ningún objeto en el lugar a menos que sea absolutamente necesario, los efectos secundarios pueden tener resultados inesperados. – tokland

Respuesta

196

Supongo que eres consciente del método Hash#except ActiveSupport añade en Hash.

Esto permitiría a su código para simplificar a:

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

Además, no tendría que parche mono, ya que el equipo de rieles lo hizo por ti!

+1

¡Ahhh, sabía que ya había visto esto antes, pero no podía recordar dónde! (De ahí mi observación de "esto no me parece bien"). ¡Gracias! –

+0

¡Nifty!Tengo que recordar este. – Jim

+3

Uno de esos métodos menos documentados. Fui buscando algo así mientras proponía una respuesta pero no la veía. – tadman

8

¿Arrancar un parche de mono?

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 
+4

Los parches de mono son una herramienta de último recurso. –

+14

Los parches de mono * que reemplazan las funciones existentes * son una herramienta de último recurso. Los parches de mono que agregan nuevas funciones son Ruby 101. –

+4

Debe ser 'delete (k)' en lugar de 'delete (key)' – Vincent

2

No sé lo que piensa que está mal con su solución propuesta. Supongo que quiere un método delete_all en Hash o algo así? Si es así, tadman's answer proporciona la solución. Pero francamente, por una sola vez, creo que su solución es extremadamente fácil de seguir. Si está utilizando esto con frecuencia, es posible que desee envolverlo en un método de ayuda.

10

Otra manera de expresar la respuesta de dmathieu podría ser

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

Creo que te refieres a 'params.delete_if {| k, v | [: controller,: action,: other_key] .include? k} ' – Telemachus

+0

Buena captura, Telémaco. – MikeSep

20

estaría completamente satisfecho con el código que envió originalmente en su pregunta.

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

sin modificar 'Hash' esta es la mejor respuesta: +1: –

40

Mientras usa Hash#except maneja su problema, tenga en cuenta que introduce potential security issues. Una buena regla empírica para manejar cualquier información de los visitantes es utilizar un enfoque de lista blanca. En este caso, usando Hash#slice en su lugar.

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

Gracias por mencionar los problemas de seguridad que rodean la redirección. –

+11

Solo un aviso: ActiveSupport, no Ruby en sí mismo, proporciona hash # slice y #slice! http://as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/Slice.html –

+1

No pude obtener el enlace de David James para que funcione, pero este parece estar bien: http://api.rubyonrails.org/ clases/Hash.html # method-i-slice –