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

Есть ли что-нибудь попроще и чище?

Марк Вестлинг
источник
Когда я писал, что второй подход не подходит, я имел в виду, что, учитывая богатство Hash API, я подозревал, что для этого уже есть какой-то метод или идиома, и патч для обезьяны не понадобится. Может быть, нет. Большое спасибо всем, кто ответил!
Марк Вестлинг
3
Hash # кроме того, что я искал. Я не помню, чтобы это было расширение ядра Rails, поэтому я был озадачен, когда не смог найти его в Hash API.
Марк Вестлинг
1
Обратите внимание, что строго ответ, Hash#except!но Hash#exceptэто путь (не связывайтесь params!). Как правило, не связывайтесь с каким-либо объектом на месте, если это не требуется, побочные эффекты могут иметь неожиданные результаты.
Tokland

Ответы:

219

Я предполагаю, что вы не знаете о Hash #, кроме метода, который ActiveSupport добавляет в Hash.

Это позволило бы упростить ваш код до:

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

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

Бен Круз
источник
1
Аааа, я знал, что видел это раньше, но я не мог вспомнить, где! (Отсюда мое замечание «это не правильно».) Спасибо!
Марк Вестлинг
3
Один из тех менее документированных методов. Я искал что-то подобное, предлагая ответ, но не видел его.
tadman
1
По какой-то причине кроме не работал. Но except!сделал. Rails 3.0
поездка
4
Rails 3.2 на атрибутах ActiveRecord, пришлось использовать строки для ключей? т.е. User.attributes.except("id", "created_at", "updated_at")символы не работали
house9
1
В дополнение к тому, что упоминалось @ house9, attributesметод ActiveRecord возвращает a Hashс ключами, которые есть 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, предоставляет Hash # slice и #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
Дэвид Дж.
1
Я не смог получить ссылку Дэвида Джеймса на работу, но, похоже, с ней все в порядке: api.rubyonrails.org/classes/Hash.html#method-i-slice
Доминик Сэйерс
неопределенный метод 'slice!' для{:b=>2, :c=>3}:Hash
Khurram Raza
25

Я был бы полностью доволен кодом, который вы изначально разместили в своем вопросе.

[:controller, :action, :other_key].each { |k| params.delete(k) }
Боб Аман
источник
без изменений Hashэто лучший ответ: +1:
Дэн Брэдбери
Я использовал этот метод, но заменил params на имя хэша, и тогда это сработало !! Хеш видоизменяется.
Пабло
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.
Дэвид Сейлер
4
Должно быть delete(k)вместоdelete(key)
Винсент
Для обслуживания кода реализация неразрушающего delete_keysдолжна быть простоdup.delete_keys!(*keys)
Phrogz
@Phrogz Определение одного в терминах другого не всегда плохая идея, но для ясности его просто оставили здесь развернутым.
tadman
2

Я не знаю, что вы думаете не так с вашим предложенным решением. Я полагаю, вы хотите delete_allметод Hash или что-то еще? Если так, то ответ Тэдмана дает решение. Но, честно говоря, я считаю, что за вашим решением очень легко следовать. Если вы используете это часто, вы можете заключить его в вспомогательный метод.

Песто
источник