Ruby on Rails: Usuń wiele kluczy mieszających

148

Często piszę to:

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

Ścieżka usuwania nie wydaje się odpowiednia, podobnie jak:

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

Czy jest coś prostszego i czystszego?

Mark Westling
źródło
Kiedy pisałem, że drugie podejście nie wydaje się właściwe, miałem na myśli, że biorąc pod uwagę bogactwo Hash API, podejrzewałem, że istnieje już jakaś metoda lub idiom do tego i małpa łatka nie byłaby konieczna. Może jednak nie. Wielkie dzięki dla wszystkich, którzy odpowiedzieli!
Mark Westling
3
Hash # z wyjątkiem był dokładnie tym, czego szukałem. Nie pamiętałem, że jest to podstawowe rozszerzenie Railsów, więc byłem zdziwiony, gdy nie mogłem go znaleźć w Hash API.
Mark Westling
1
Zwróć uwagę, że odpowiedź brzmi, Hash#except!ale Hash#exceptjest drogą do zrobienia (nie zadzieraj params!). Z reguły nie rób bałaganu z żadnym obiektem na miejscu, chyba że jest to absolutnie wymagane, ponieważ efekty uboczne mogą mieć nieoczekiwane rezultaty.
tokland

Odpowiedzi:

219

Domyślam się, że nie jesteś świadomy Hash # z wyjątkiem metody ActiveSupport, która dodaje do Hash.

Pozwoliłoby to na uproszczenie kodu do:

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

Nie musiałbyś też małpować łatek, ponieważ zespół Rails zrobił to za Ciebie!

Ben Crouse
źródło
1
Ahhh, wiedziałem, że już to widziałem, ale nie pamiętałem gdzie! (Stąd moja uwaga „to nie jest właściwe”.) Dzięki!
Mark Westling
3
Jedna z tych mniej udokumentowanych metod. Szukałem czegoś takiego, proponując odpowiedź, ale jej nie widziałem.
tadman
1
Z jakiegoś powodu, z wyjątkiem tego, że nie zadziałało. Ale except!zrobił. Rails 3.0
Trip
4
Railsy 3.2 na atrybutach ActiveRecord, musiały używać ciągów znaków dla kluczy? tzn. User.attributes.except("id", "created_at", "updated_at")symbole nie działały
house9
1
Dodając do tego, o czym wspomniał @ house9, attributesmetoda ActiveRecord zwraca a Hashz kluczami, które są String. Więc wtedy musiałbyś używać nazw kluczy w .except(). Jednak Hash.symbolize_keys@user.attributes.symbolize_keys.except(:password, :notes)symbolize_keys
omijam
44

Podczas używania Hash#exceptrozwiązuje problem, pamiętaj, że wprowadza potencjalne problemy z bezpieczeństwem . Dobrą praktyczną zasadą postępowania z danymi od odwiedzających jest użycie metody białej listy. W tym przypadku użycie Hash#slicezamiast.

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)
jsa
źródło
1
Dziękujemy za wspomnienie o problemach z bezpieczeństwem związanych z przekierowaniem.
David J.
12
Tylko jedno ostrzeżenie: ActiveSupport, a nie sam Ruby, zapewnia Hash # slice i #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.
1
Nie mogłem pobrać linku Davida Jamesa do pracy, ale ten wydaje się być w porządku: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers
niezdefiniowana metoda „plasterek!” dla{:b=>2, :c=>3}:Hash
Khurram Raza
25

Byłbym całkowicie zadowolony z kodu, który zamieściłeś w swoim pytaniu.

[:controller, :action, :other_key].each { |k| params.delete(k) }
Bob Aman
źródło
bez modyfikowania Hashto najlepsza odpowiedź: +1:
Dan Bradbury
Użyłem tej metody, ale zamieniłem parametry na nazwę skrótu i ​​zadziałało !! Skrót zostaje zmutowany.
Pablo
13

Innym sposobem wyrażenia odpowiedzi dmathieu może być

params.delete_if { |k,v| [:controller, :action, :other_key].include? k }
Mike Seplowitz
źródło
8

Odpalić małpę?

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
źródło
5
Plasterki małp są narzędziem ostatniej szansy.
Bob Aman
15
Łatki Monkey, które zastępują istniejące funkcje, są narzędziem ostatniej szansy. Łatki Monkey, które dodają nowe funkcje, to Ruby 101.
David Seiler
4
Powinien być delete(k)zamiastdelete(key)
Vincent
Aby delete_keyszachować kod, implementacja nieniszczącej powinna być prostadup.delete_keys!(*keys)
Phrogz
@Phrogz Definiowanie jednego w kategoriach drugiego nie zawsze jest złym pomysłem, ale dla jasności zostało to po prostu rozwinięte.
tadman
2

Nie wiem, co Twoim zdaniem jest niewłaściwe w proponowanym rozwiązaniu. Przypuszczam, że chcesz delete_allmetodę na Hash czy coś? Jeśli tak, odpowiedź Tadmana dostarcza rozwiązania. Ale szczerze, jednorazowo, myślę, że twoje rozwiązanie jest niezwykle łatwe do zastosowania. Jeśli używasz tego często, możesz chcieć zawrzeć to w metodzie pomocniczej.

pesto
źródło