ChatGPT解决这个技术问题 Extra ChatGPT

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

有什么更简单更干净的吗?

当我写到第二种方法感觉不对时,我的意思是考虑到 Hash API 的丰富性,我怀疑已经有一些方法或习语可以解决这个问题,并且不需要猴子补丁。不过,也许不是。非常感谢所有回答的人!
Hash#except 正是我想要的。我不记得它是 Rails 核心扩展,所以当我在 Hash API 中找不到它时,我感到很困惑。
请注意,严格来说答案是 Hash#except!Hash#except 是要走的路(不要与 params 混淆!)。根据经验,除非绝对需要,否则不要就地处理任何对象,副作用可能会产生意想不到的结果。

D
Dominic Sayers

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

它可以让您的代码简化为:

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

此外,您不必修改补丁,因为 Rails 团队已经为您完成了!


啊,我知道我以前见过这个,但我不记得在哪里! (因此我的“这感觉不对”评论。)谢谢!
那些记录较少的方法之一。我在提出答案时去寻找类似的东西,但没有看到。
由于某种原因,除了没有工作。但是 except! 做到了。导轨 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 使其按预期工作
F
Fralcon

在使用 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
B
Bob Aman

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

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

不修改 Hash 这是最好的答案:+1:
我已经使用了这种方法,但是用哈希的名称替换了 params,然后它就起作用了!!哈希值发生突变。
M
Mike Seplowitz

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

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

M
MrYoshiji

启动猴子补丁?

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 根据另一个定义一个并不总是一个坏主意,但为了清楚起见,它只是留在这里展开。
C
Community

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


t
the_spectator

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

从文档:

哈希#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