Ruby on Rails:删除多个哈希键

Posted

技术标签:

【中文标题】Ruby on Rails:删除多个哈希键【英文标题】:Ruby on Rails: Delete multiple hash keys 【发布时间】:2010-12-06 08:15:25 【问题描述】:

我经常发现自己在写这个:

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 的丰富性,我怀疑已经有一些方法或习语可以解决这个问题,还有一个猴子补丁没有必要。不过,也许不是。非常感谢所有回答的人! Hash#except 正是我想要的。我不记得它是 Rails 核心扩展,所以当我在 Hash API 中找不到它时,我感到很困惑。 请注意,严格来说答案是Hash#except!,但Hash#except 才是正确的选择(不要与params 混淆!)。根据经验,除非绝对需要,否则不要就地处理任何对象,副作用可能会产生意想不到的结果。 【参考方案1】:

我猜你不知道 ActiveSupport 添加到 Hash 的 Hash#except 方法。

这将使您的代码简化为:

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

此外,您不必进行猴子补丁,因为 Rails 团队已经为您完成了!

【讨论】:

啊,我知道我以前见过这个,但我不记得在哪里! (因此我的“这感觉不对”的话。)谢谢! 其中一种记录较少的方法。我在提出答案时去寻找类似的东西,但没有看到。 由于某种原因,除了没有工作。但是except! 做到了。 Rails 3.0 Rails 3.2 关于 ActiveRecord 属性,必须使用字符串作为键?即User.attributes.except("id", "created_at", "updated_at") 符号不起作用 除了@house9 提到的内容之外,ActiveRecord attributes 方法返回一个Hash,其键为String。那么你必须在.except() 中使用字符串键名。但是,我使用 Hash.symbolize_keys a la @user.attributes.symbolize_keys.except(:password, :notes) 解决了这个问题 - 使用 symbolize_keys 使其按预期工作【参考方案2】:

虽然使用Hash#except 可以解决您的问题,但请注意它引入了potential security issues。处理来自访问者的任何数据的一个好的经验法则是使用白名单方法。在这种情况下,请改用Hash#slice

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

【讨论】:

感谢您提及有关重定向的安全问题。 请注意:ActiveSupport,而不是 Ruby 本身,提供了 Hash#slice 和#slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/… 我无法使用 David James 的链接,但这个似乎没问题:api.rubyonrails.org/classes/Hash.html#method-i-slice 未定义方法“切片!”对于:b=>2, :c=>3:Hash【参考方案3】:

我会对您最初在问题中发布的代码感到非常满意。

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

【讨论】:

不修改Hash这是最好的答案:+1: 我用过这个方法,但是用哈希的名字替换了params,然后就成功了!!哈希值发生了变异。【参考方案4】:

另一种表达 dmathieu 答案的方式可能是

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

【讨论】:

【参考方案5】:

启动猴子补丁?

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 101。 应该是delete(k) 而不是delete(key) 对于代码维护,非破坏性delete_keys 的实现应该是简单的dup.delete_keys!(*keys) @Phrogz 根据另一个定义一个并不总是一个坏主意,但为了清楚起见,它只是放在这里展开。【参考方案6】:

我不知道您认为您提出的解决方案有什么问题。我想你想要 Hash 上的 delete_all 方法还是什么?如果是这样,tadman's answer 提供了解决方案。但坦率地说,对于一次性的,我认为您的解决方案非常容易遵循。如果您经常使用它,您可能希望将其包装在一个辅助方法中。

【讨论】:

【参考方案7】:

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

来自文档:

Hash#except(*keys) → 哈希

此方法返回一个新哈希,其中包括原始哈希中除给定键之外的所有内容。

示例:

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

【讨论】:

以上是关于Ruby on Rails:删除多个哈希键的主要内容,如果未能解决你的问题,请参考以下文章

作物哈希结构:Ruby on rails

如何在 ruby​​ on rails 中集成多个支付网关(多个商家)?

如何在 ruby​​ on rails 中结合救援多个异常?

Ruby-on-Rails:多个 has_many :通过可能吗?

向 Ruby 中的键添加多个值以及仅删除一个关联的值

paypal gem 多个帐户 ruby​​ on rails