Disons que j'ai un objet Gift
avec @name = "book"
& @price = 15.95
. Quel est le meilleur moyen de convertir cela en Hash {name: "book", price: 15.95}
en Ruby, pas en Rails (bien que vous puissiez aussi donner la réponse à Rails)?
class Gift
def initialize
@name = "book"
@price = 15.95
end
end
gift = Gift.new
hash = {}
gift.instance_variables.each {|var| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}
Alternativement avec each_with_object
:
gift = Gift.new
hash = gift.instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}
Il suffit de dire (objet actuel) .attributes
.attributes
renvoie une hash
de toute object
. Et c'est beaucoup plus propre aussi.
Implémenter #to_hash
?
class Gift
def to_hash
hash = {}
instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var) }
hash
end
end
h = Gift.new("Book", 19).to_hash
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}
Pour les objets d'enregistrement actifs
module ActiveRecordExtension
def to_hash
hash = {}; self.attributes.each { |k,v| hash[k] = v }
return hash
end
end
class Gift < ActiveRecord::Base
include ActiveRecordExtension
....
end
class Purchase < ActiveRecord::Base
include ActiveRecordExtension
....
end
et ensuite il suffit d'appeler
gift.to_hash()
purch.to_hash()
class Gift
def to_hash
instance_variables.map do |var|
[var[1..-1].to_sym, instance_variable_get(var)]
end.to_h
end
end
Si vous n'êtes pas dans un environnement Rails (c'est-à-dire que vous n'avez pas ActiveRecord disponible), cela peut être utile:
JSON.parse( object.to_json )
Vous pouvez utiliser la méthode as_json
. Cela convertira votre objet en hash.
Mais, ce hachage viendra comme une valeur pour le nom de cet objet en tant que clé. Dans ton cas,
{'gift' => {'name' => 'book', 'price' => 15.95 }}
Si vous avez besoin d'un hachage stocké dans l'objet, utilisez as_json(root: false)
. Je pense que par défaut root sera faux. Pour plus d'informations, consultez le guide officiel Ruby
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
Vous pouvez écrire une solution très élégante en utilisant un style fonctionnel.
class Object
def hashify
Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }]
end
end
Convertissez vos objets en hachage de manière récursive en utilisant une gemme 'hashable' ( https://rubygems.org/gems/hashable ) Example
class A
include Hashable
attr_accessor :blist
def initialize
@blist = [ B.new(1), { 'b' => B.new(2) } ]
end
end
class B
include Hashable
attr_accessor :id
def initialize(id); @id = id; end
end
a = A.new
a.to_dh # or a.to_deep_hash
# {:blist=>[{:id=>1}, {"b"=>{:id=>2}}]}
Peut-être envie d'essayer instance_values
. Cela a fonctionné pour moi.
Vous devez remplacer la méthode inspect
de votre objet pour renvoyer le hachage souhaité, ou simplement implémenter une méthode similaire sans remplacer le comportement de l'objet par défaut.
Si vous voulez vous perfectionner, vous pouvez parcourir les variables d'instance d'un objet avec object.instance_variables
Produit une copie superficielle en tant qu'objet de hachage contenant uniquement les attributs de modèle
my_hash_gift = gift.attributes.dup
Vérifier le type de l'objet résultant
my_hash_gift.class
=> Hash
Gift.new.attributes.symbolize_keys
J'ai commencé à utiliser des structures pour faciliter le hachage des conversions. Au lieu d'utiliser une structure nue, je crée ma propre classe dérivée d'un hachage, ce qui vous permet de créer vos propres fonctions et de documenter les propriétés d'une classe.
require 'ostruct'
BaseGift = Struct.new(:name, :price)
class Gift < BaseGift
def initialize(name, price)
super(name, price)
end
# ... more user defined methods here.
end
g = Gift.new('pearls', 20)
g.to_h # returns: {:name=>"pearls", :price=>20}
Pour ce faire sans Rails, une méthode simple consiste à stocker les attributs sur une constante.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
end
Et puis, pour convertir une instance de Gift
en Hash
, vous pouvez:
class Gift
...
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
C'est un bon moyen de faire cela car cela n'inclura que ce que vous définissez sur attr_accessor
, et pas toutes les variables d'instance.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
def create_random_instance_variable
@xyz = 123
end
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
g = Gift.new
g.name = "Foo"
g.price = 5.25
g.to_h
#=> {:name=>"Foo", :price=>5.25}
g.create_random_instance_variable
g.to_h
#=> {:name=>"Foo", :price=>5.25}
Vous devriez essayer Hashie, un joyau merveilleux: https://github.com/intridea/hashie
Si vous avez besoin que des objets imbriqués soient également convertis.
# @fn to_hash obj {{{
# @brief Convert object to hash
#
# @return [Hash] Hash representing converted object
#
def to_hash obj
Hash[obj.instance_variables.map { |key|
variable = obj.instance_variable_get key
[key.to_s[1..-1].to_sym,
if variable.respond_to? <:some_method> then
hashify variable
else
variable
end
]
}]
end # }}}