Ruby on Rails: Видаліть декілька хеш-клавіш


148

Мені часто доводиться писати таке:

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

Слід делетів не вважається правильним, а також:

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

Чи є щось простіше і чистіше?


Коли я писав, що другий підхід не вважає себе правильним, я мав на увазі, що враховуючи багатство API Hash, я підозрював, що для цього вже є якийсь метод або ідіома, і патч мавпи не знадобиться. Можливо, ні. Велике спасибі всім, хто відповів!
Марк Вестлінг

3
Hash # за винятком було саме те, що я шукав. Я не пам’ятав, що це основне розширення Rails, тому я був спантеличений, коли не зміг його знайти в API Hash.
Марк Вестлінг

1
Зауважте, що суворо відповідь, Hash#except!але Hash#exceptце шлях, який потрібно пройти (не возитися з цим params!). Як правило, не возиться з будь-яким об'єктом на місці, якщо це абсолютно не потрібно, побічні ефекти можуть мати несподівані результати.
tokland

Відповіді:


219

Я здогадуюсь, що ви не знаєте Hash #, за винятком методу ActiveSupport, який додає до Hash.

Це дозволить спростити ваш код до:

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

Крім того, вам не доведеться маніпулювати патч, оскільки команда Rails зробила це за вас!


1
А-а-а, я знав, що бачив це раніше, але не міг пригадати, де! (Отже, моє зауваження "це не вірно".) Дякую!
Марк Вестлінг

3
Один з таких менш задокументованих методів. Я пішов шукати щось подібне, пропонуючи відповідь, але не бачив.
тадман

1
Чомусь, крім того, не працювало. Але except!зробив. Rails 3.0
Поїздка

4
Rails 3.2 за атрибутами ActiveRecord, повинні були використовувати рядки для клавіш? тобто User.attributes.except("id", "created_at", "updated_at")символи не спрацювали
house9

1
Додавши до згадуваного @ house9 attributesметод ActiveRecord повертає Hashклавіші a, які є String. Тоді вам доведеться використовувати імена ключових рядків у .except(). Однак я обіходжу це за допомогою Hash.symbolize_keysа-ля@user.attributes.symbolize_keys.except(:password, :notes)symbolize_keys
обіходжу

44

Під час використання Hash#except вирішення вашої проблеми, пам’ятайте, що вона вводить потенційні проблеми безпеки . Добре правило для обробки будь-яких даних відвідувачів - це використовувати підхід із білого списку. У цьому випадку, використовуючи Hash#sliceзамість цього.

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

1
Дякуємо, що згадали про проблеми безпеки щодо переадресації.
Девід Дж.

12
Лише вгору: ActiveSupport, а не Ruby, забезпечує хеш-шматочок і #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.

1
Я не зміг отримати посилання Девіда Джеймса на роботу, але це, здається, все в порядку: api.rubyonrails.org/classes/Hash.html#method-i-slice
Домінік

невизначений метод 'скибочка!' за{:b=>2, :c=>3}:Hash
Хуррам Раза

25

Буду повністю задоволений кодом, який ви спочатку опублікували у своєму запитанні.

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

не змінюючи Hashце найкраща відповідь: +1:
Ден Бредбері

Я використовував цей метод, але замінив парами на ім'я хеша, а потім він працював !! Хеш мутується.
Пабло

13

Іншим способом висловити відповідь дматьє може бути

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

8

Розпалити патч мавпи?

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
Пластири мавп - це останній засіб.
Боб Аман

15
Патчі мавп, які замінюють існуючі функції, є останнім засобом. Патчі мавп, які додають нові функції, - Ruby 101.
David Seiler

4
Має бути delete(k)замістьdelete(key)
Вінсент

Для підтримки коду реалізація неруйнівного характеру delete_keysповинна бути простоdup.delete_keys!(*keys)
Фрогз

@Phrogz Визначення одного з точки зору іншого не завжди є поганою ідеєю, але це просто залишається тут розкрученим для ясності.
тадман

2

Я не знаю, що ви вважаєте неправильним із запропонованим вами рішенням. Я думаю, ви хочете delete_allметод на Хеш чи щось таке? Якщо так, відповідь тадмана забезпечує рішення. Але, чесно кажучи, для разового, я вважаю, що ваше рішення слідує надзвичайно просто. Якщо ви використовуєте це часто, можливо, вам захочеться перетворити його в допоміжний метод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.