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#except正是我想要的。我不记得它是Rails核心扩展,所以当我在Hash API中找不到它时,我感到很困惑。
马克韦斯特林

1
请注意,严格的答案是,Hash#except!但这Hash#except只是解决的办法(不要惹恼params!)。根据经验,除非绝对需要,否则请勿在原地弄乱任何物体,否则副作用可能会带来意想不到的结果。
tokland

Answers:


219

我猜你不知道哈希值,除了 ActiveSupport向Hash添加的方法。

它将使您的代码简化为:

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

另外,由于Rails团队为您完成了修补程序,因此您不必胡闹!


1
啊,我知道我以前见过这个,但是我不记得在哪里!(因此,我说“这感觉不对”)。谢谢!
马克韦斯特林

3
那些文献较少的方法之一。在提出答案时,我一直在寻找类似的东西,但没有看到。
tadman

1
由于某种原因,除了没有用。但是except!做到了。Rails 3.0
2012年

4
Rails 3.2上有ActiveRecord属性,必须使用字符串作为键吗?即User.attributes.except("id", "created_at", "updated_at")符号不起作用
house9 2012年

1
除了@ house9提到的内容外,ActiveRecord attributes方法还返回一个Hash键为的String。因此,您将不得不在中使用字符串键名.except()。不过我解决这个使用Hash.symbolize_keys一拉@user.attributes.symbolize_keys.except(:password, :notes)-使用symbolize_keys使得它的工作正如人们所预料
FireDragon

44

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

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

1
感谢您提到有关重定向的安全问题。
David J.

12
请注意:ActiveSupport提供了Hash#slice和#slice,而不是Ruby本身!as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…–
David J.

1
我无法获得David James的工作链接,但这个链接似乎还可以:api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers

未定义的方法“切片!” for{:b=>2, :c=>3}:Hash
Khurram Raza

25

我对您最初在问题中发布的代码完全满意。

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

不修改Hash这是最好的答案:+1:
丹·布拉德伯里

我已经使用了这种方法,但是用哈希的名称替换了params,然后它起作用了!!哈希被突变。
Pablo

13

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

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
替代现有功能的猴子补丁不得已的工具。猴子补丁增加新的功能是红宝石101
戴维·塞勒

4
应该delete(k)代替delete(key)
Vincent 2010年

对于代码维护,非破坏性实现delete_keys应该很简单dup.delete_keys!(*keys)
Phrogz

@Phrogz用另一个定义一个并不总是一个坏主意,但是为了清楚起见,这里只是展开了它。
tadman

2

我不知道您认为建议的解决方案有什么问题。我想您想要使用delete_allHash或其他方法?如果是这样,塔德曼的答案提供了解决方案。但是坦率地说,我认为您的解决方案非常容易遵循。如果您经常使用此功能,则可能需要将其包装在辅助方法中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.