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?


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ê!


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)

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) }

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 }

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

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.