Ruby on Rails: Exclua várias chaves de hash

148

Costumo encontrar-me escrevendo isso:

params.delete(:controller)  
params.delete(:action)  
params.delete(:other_key)  
redirect_to my_path(params)  

A trilha de exclusões não parece certa e nem:

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

Existe algo mais simples e limpo?

Mark Westling
fonte
Quando escrevi que a segunda abordagem não parecia certa, eu quis dizer que, dada a riqueza da API Hash, suspeitei que já houvesse algum método ou idioma disponível para isso e que um patch para macacos não seria necessário. Talvez não, no entanto. Muito obrigado a todos que responderam!
22620 Mark Westling
3
Hash # exceto era exatamente o que eu estava procurando. Eu não lembrava que era uma extensão principal do Rails, então fiquei confusa quando não consegui encontrá-la na API Hash.
22420 Mark Westling
1
Observe que, estritamente, a resposta é, Hash#except!mas Hash#excepté o caminho a seguir (não mexa params!). Como regra geral, não mexa com nenhum objeto no local, a menos que seja absolutamente necessário, os efeitos colaterais podem ter resultados inesperados.
tokland

Respostas:

219

Suponho que você desconheça o Hash #, exceto o método que o ActiveSupport adiciona ao Hash.

Isso permitiria que seu código fosse simplificado para:

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

Além disso, você não precisaria atualizar o patch, pois a equipe do Rails fez isso por você!

Ben Crouse
fonte
1
Ahhh, eu sabia que já tinha visto isso antes, mas não conseguia me lembrar onde! (Daí a minha observação "isso não parece certo".) Obrigado!
22420 Mark Westling
3
Um desses métodos menos documentados. Procurei algo assim ao propor uma resposta, mas não a vi.
Tadman
1
Por alguma razão, exceto não funcionou. Mas except!fez. Rails 3.0
Viagem
4
Rails 3.2 nos atributos ActiveRecord, teve que usar strings para as chaves? ou seja, os User.attributes.except("id", "created_at", "updated_at")símbolos não funcionaram
house9
1
Adicionando o que @ house9 mencionou, o attributesmétodo ActiveRecord retorna a Hashcom chaves que são String. Então você teria que usar os nomes das chaves de string .except(). No entanto, eu contornar isso usando a Hash.symbolize_keysla @user.attributes.symbolize_keys.except(:password, :notes)- usando symbolize_keysfaz com que funcione como seria de esperar
FireDragon
44

Enquanto o uso Hash#exceptlida com o seu problema, lembre-se de que ele apresenta possíveis problemas de segurança . Uma boa regra para lidar com os dados dos visitantes é usar uma abordagem da lista de permissões. Nesse caso, usando em Hash#slicevez disso.

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)
jsa
fonte
1
Obrigado por mencionar os problemas de segurança que envolvem o redirecionamento.
David J.
12
Apenas um alerta: o ActiveSupport, não o próprio Ruby, fornece Hash # slice e #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/…
David J.
1
Eu não poderia obter link de David James para o trabalho, mas este parece ser ok: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers
método indefinido 'fatia!' for{:b=>2, :c=>3}:Hash
Khurram Raza
25

Ficaria completamente satisfeito com o código que você postou originalmente em sua pergunta.

[:controller, :action, :other_key].each { |k| params.delete(k) }
Bob Aman
fonte
sem modificar Hashesta é a melhor resposta: +1:
Dan Bradbury
Eu usei esse método, mas substitui params pelo nome do hash e funcionou !! O hash é alterado.
24419 Pablo Pablo
13

Outra maneira de expressar a resposta de dmathieu pode ser

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

Acender um patch de macaco?

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
tadman
fonte
5
As manchas de macaco são uma ferramenta de último recurso.
22610 Bob Aman
15
Os patches de macaco que substituem as funções existentes são uma ferramenta de último recurso. Patches de macaco que adicionam novas funções são Rubi 101.
David Seiler
4
Deve ser delete(k)em vez dedelete(key)
Vincent
Para manutenção de código, a implementação do sistema não destrutivo delete_keys deve ser simplesmentedup.delete_keys!(*keys)
Phrogz
@Phrogz Definir um em termos do outro nem sempre é uma má idéia, mas é deixado aqui desenrolado para maior clareza.
14
2

Não sei o que você acha que está errado com sua solução proposta. Suponho que você queira um delete_allmétodo no Hash ou algo assim? Nesse caso, a resposta de tadman fornece a solução. Mas, francamente, por uma única vez, acho que sua solução é extremamente fácil de seguir. Se você estiver usando isso com frequência, convém agrupá-lo em um método auxiliar.

Pesto
fonte