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

还有比这更简单更干净的吗?

77194 次浏览

弄个猴子围栏?

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

我不知道你认为你提出的解决方案有什么问题。我猜你想要一个 delete_all方法对散列或东西?如果是这样,Tadman 的回答提供了解决方案。但坦白地说,作为一次性的,我认为你的解决方案非常容易实现。如果您经常使用这种方法,那么您可能需要将它包装在一个 helper 方法中。

用另一种方式来表达德马修的答案可能是

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

我对你最初在问题中发布的代码非常满意。

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

我猜您不知道 ActiveSupport 添加到 Hash 的 除了方法。

它将使您的代码简化为:

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

而且,您也不需要猴子补丁,因为 Rails 团队已经为您做到了这一点!

当使用 Hash#except处理您的问题时,请注意它引入了 潜在的安全问题。处理来自访问者的任何数据的一个很好的经验法则是使用白名单方法。在这种情况下,改用 Hash#slice

params.slice!(:param_to_keep_1, :param_to_keep_2)
redirect_to my_path(params)

从 Ruby 3.0开始,直接支持 Hash#except,这意味着我们不需要 activessupport 来访问 Hash#except

来自文档:

除了(* key)→ Hash

此方法返回一个新散列,该散列包含除给定键之外的原始散列中的所有内容。

例如:

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