Ruby on Rails: Löschen Sie mehrere Hash-Schlüssel

148

Ich schreibe oft Folgendes:

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

Die Spur der Löschungen fühlt sich nicht richtig an und auch nicht:

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

Gibt es etwas einfacheres und saubereres?

Mark Westling
quelle
Als ich schrieb, dass sich der zweite Ansatz nicht richtig anfühlte, meinte ich, dass ich angesichts des Reichtums der Hash-API vermutete, dass es dafür bereits eine Methode oder Redewendung gibt und ein Affen-Patch nicht notwendig wäre. Vielleicht aber auch nicht. Vielen Dank an alle, die geantwortet haben!
Mark Westling
3
Hash # außer war genau das, wonach ich gesucht habe. Ich habe mich nicht daran erinnert, dass es sich um eine Rails-Kernerweiterung handelt, daher war ich verwirrt, als ich sie in der Hash-API nicht finden konnte.
Mark Westling
1
Beachten Sie, dass genau die Antwort ist, Hash#except!aber Hash#exceptder richtige Weg ist (spielen Sie nicht mit params!). Als Faustregel gilt, dass Sie mit keinem Objekt an Ort und Stelle herumspielen dürfen, es sei denn, dies ist unbedingt erforderlich. Die Nebenwirkungen können zu unerwarteten Ergebnissen führen.
Tokand

Antworten:

219

Ich vermute, Sie kennen die Hash-Nummer nur Methode, die ActiveSupport zu Hash hinzufügt.

Dadurch kann Ihr Code vereinfacht werden, um:

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

Außerdem müssten Sie keinen Affen-Patch ausführen, da das Rails-Team dies für Sie erledigt hat!

Ben Crouse
quelle
1
Ahhh, ich wusste, dass ich das schon einmal gesehen hatte, aber ich konnte mich nicht erinnern, wo! (Daher meine Bemerkung "Das fühlt sich nicht richtig an".) Danke!
Mark Westling
3
Eine dieser weniger dokumentierten Methoden. Ich suchte nach so etwas, während ich eine Antwort vorschlug, sah sie aber nicht.
Tadman
1
Aus irgendeinem Grund außer hat nicht funktioniert. Aber except!tat es. Rails 3.0
Trip
4
Musste Rails 3.2 für ActiveRecord-Attribute Zeichenfolgen für die Schlüssel verwenden? dh User.attributes.except("id", "created_at", "updated_at")Symbole funktionierten nicht
house9
1
Zusätzlich zu dem, was @ house9 erwähnt hat, attributesgibt die ActiveRecord- Methode a Hashmit Schlüsseln zurück, die sind String. Dann müssten Sie also String-Schlüsselnamen in verwenden .except(). Ich komme jedoch mit dem Hash.symbolize_keysa la @user.attributes.symbolize_keys.except(:password, :notes)- using symbolize_keys
darum
44

Beachten Sie bei der Verwendung Hash#exceptIhres Problems, dass dadurch potenzielle Sicherheitsprobleme auftreten . Eine gute Faustregel für den Umgang mit Daten von Besuchern ist die Verwendung eines Whitelist-Ansatzes. In diesem Fall mitHash#slice stattdessen.

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)
jsa
quelle
1
Vielen Dank, dass Sie die Sicherheitsprobleme im Zusammenhang mit der Umleitung erwähnt haben.
David J.
12
Nur ein Kopf hoch: ActiveSupport, nicht Ruby selbst, bietet Hash # Slice und # Slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.
1
Ich konnte David James 'Link nicht zum Laufen bringen,
Dominic Sayers
undefinierte Methode 'Slice!' für{:b=>2, :c=>3}:Hash
Khurram Raza
25

Ich wäre mit dem Code, den Sie ursprünglich in Ihrer Frage gepostet haben, völlig zufrieden.

[:controller, :action, :other_key].each { |k| params.delete(k) }
Bob Aman
quelle
ohne Hash
Dan Bradbury
Ich habe diese Methode verwendet, aber die Parameter durch den Namen des Hashs ersetzt und dann hat es funktioniert !! Der Hash wird mutiert.
Pablo
13

Eine andere Möglichkeit, die Antwort von dmathieu zu formulieren, könnte sein

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

Einen Affenfeld anfeuern?

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
Tadman
quelle
5
Affenpflaster sind ein Werkzeug der letzten Instanz.
Bob Aman
15
Affen-Patches , die vorhandene Funktionen ersetzen, sind das letzte Mittel. Affen-Patches, die neue Funktionen hinzufügen, sind Ruby 101.
David Seiler
4
Sollte delete(k)statt seindelete(key)
Vincent
Für die Code-Wartung sollte die Implementierung des zerstörungsfreien delete_keyseinfach seindup.delete_keys!(*keys)
Phrogz
@Phrogz Es ist nicht immer eine schlechte Idee, eines in Bezug auf das andere zu definieren, aber es wird hier aus Gründen der Klarheit nur abgewickelt.
Tadman
2

Ich weiß nicht, was Ihrer Meinung nach mit Ihrer vorgeschlagenen Lösung falsch ist. Ich nehme an, Sie wollen eine delete_allMethode für Hash oder so? Wenn ja, bietet Tadmans Antwort die Lösung. Aber ehrlich gesagt, für eine einmalige Sache denke ich, dass Ihre Lösung extrem einfach zu befolgen ist. Wenn Sie dies häufig verwenden, möchten Sie es möglicherweise in eine Hilfsmethode einbinden.

Pesto
quelle