Question

Quand j'ASSIGN mon contrôleur

@my_hash = { :my_key => :my_value }

et vérifiez que le contrôleur en faisant

get 'index'
assigns(:my_hash).should == { :my_key => :my_value }

alors je reçois le message d'erreur suivant:

expected: {:my_key=>:my_value},
got: {"my_key"=>:my_value} (using ==)

Pourquoi ce symbole automatique à la conversion de chaîne se produire? Pourquoi affecte-t-elle la clé du hachage?

Était-ce utile?

La solution

Il peut finir comme HashWithIndifferentAccess si Rails obtient en quelque sorte Ahold, et que les utilisations chaîne interne clés. Vous pouvez vérifier la classe est le même:

assert_equal Hash, assigns(:my_hash).class

Les paramètres sont toujours traités comme le type d'accès indifférent de hachage de sorte que vous pouvez récupérer en utilisant soit la chaîne ou le symbole. Si vous affectez ceci à votre params hachage sur le get ou composez le post, ou vous pourriez se convertir.

Une autre chose que vous pouvez faire est de geler et de voir si les tentatives de quiconque de le modifier parce que devrait lancer une exception:

@my_hash = { :my_key => :my_value }.freeze

Autres conseils

Vous pouvez essayer d'appeler "stringify_keys":

assigns(:my_hash).should == { :my_key => :my_value }.stringify_keys

AHA! Cela se passe pas à cause de rails, en soi, mais à cause de Rspec.

J'ai eu le même problème de tester la valeur d'un Hashie::Mash dans une spécification du contrôleur (mais il applique à tout ce qui caquette comme un Hash)

Plus précisément, dans une spécification du contrôleur, lorsque vous appelez assigns pour accéder aux variables d'instance définies dans l'action du contrôleur, il ne revient pas exactement la variable d'instance définie, mais plutôt, une copie de la variable qui stocke Rspec en tant que membre un HashWithIndifferentAccess (contenant toutes les variables d'instance attribuées). Malheureusement, lorsque vous tenez un Hash (ou quoi que ce soit qui hérite de Hash) dans un HashWithIndifferentAccess, il est automatiquement converti en une instance de même, oh-so-pratique, mais pas tout à fait exact classe:)

Le plus de travail autour est d'éviter la conversion en accédant directement à la variable, avant qu'il ne soit converti « pour votre commodité », en utilisant: controller.view_assigns['variable_name'] (note: la clé ici doit être une chaîne, pas un symbole)

le test dans le message original doit passer si elle a été changée en:

get 'index'
controller.view_assigns['my_hash'].should == { :my_key => :my_value }

(bien sûr, .should ne prend plus en charge les nouvelles versions de RSpec, mais juste pour la comparaison je l'ai gardé le même)

Voir cet article pour plus d'explications: http://ryanogles.by/rails/hashie/rspec/testing/2012/12/26/rails-controller-specs-dont-always-play-nice-with-hashie.html

Je sais que cela est vieux, mais si vous mettez à niveau de Rails 3 à 4, vos tests de contrôleur peut encore avoir des endroits où Hash avec les touches de symbole a été utilisé, mais par rapport à la version de chaîne de caractères, juste pour éviter l'attente erronée.

Rails-4 a résolu ce problème: https://github.com/rails/rails / pull / 5082 . Je suggère de mettre à jour vos tests pour avoir des attentes contre les clés réelles.

Dans Rails-3 la méthode assigns convertit votre @my_hash à HashWithIndifferentAccess que stringifies toutes les clés -

def assigns(key = nil)
  assigns = @controller.view_assigns.with_indifferent_access
  key.nil? ? assigns : assigns[key]
end

https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/testing/test_process.rb#L7-L10

Rails-4 mis à jour pour retourner les clés d'origine -

def assigns(key = nil)
  assigns = {}.with_indifferent_access
  @controller.view_assigns.each { |k, v| assigns.regular_writer(k, v) }
  key.nil? ? assigns : assigns[key]
end

https://github.com/rails/rails/blob/4-0-stable/actionpack/lib/action_dispatch/testing/test_process.rb#L7-L11

Vous pouvez également passer votre objet Hash à l'initialiseur de HashWithIndifferentAccess.

Vous pouvez utiliser HashWithIndifferentAccess.new comme init Hash:

Thor::CoreExt::HashWithIndifferentAccess.new( to: 'mail@somehost.com', from: 'from@host.com')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top