Ruby on Rails: удалить несколько ключей хеша

Я часто пишу это:

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

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

7 ответов

Решение

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

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

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

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

При использовании Hash#except решает вашу проблему, имейте в виду, что это создает потенциальные проблемы безопасности. Хорошее эмпирическое правило для обработки любых данных от посетителей заключается в использовании подхода белого списка. В этом случае, используя Hash#slice вместо.

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

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

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

Другой способ сформулировать ответ дматью:

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

Запустить обезьяну?

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

Начиная с Ruby 3.0, поддерживается напрямую. Это означает, что нам не потребуется activesupport для доступа Hash#except.

Из документации:

Хэш # кроме (* ключей) → хеш

Этот метод возвращает новый хеш, который включает в себя все из исходного хеша, кроме указанных ключей.

пример:

      h = { a: 100, b: 200, c: 300, d: 400 }
h.except(:a, :d) #=> {:b=>200, :c=>300}

Справка:

https://docs.ruby-lang.org/en/3.0.0/Hash.html#method-i-except

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

Другие вопросы по тегам