Nehmen wir an, ich habe ein Gift
-Objekt mit @name = "book"
& @price = 15.95
. Was ist der beste Weg, das in Ruby in Hash {name: "book", price: 15.95}
umzuwandeln, nicht in Rails (obwohl Sie den Rails auch eine Antwort geben können)?
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}
Alternativ mit 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}
Sagen Sie einfach (aktuelles Objekt) .attributes
.attributes
gibt eine hash
einer beliebigen object
zurück. Und es ist auch viel sauberer.
#to_hash
implementieren?
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}
Für aktive Datensatzobjekte
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
und dann einfach anrufen
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
Wenn Sie sich nicht in einer Rails-Umgebung befinden (dh ActiveRecord nicht verfügbar ist), kann dies hilfreich sein:
JSON.parse( object.to_json )
Sie können die as_json
-Methode verwenden. Es wird Ihr Objekt in Hash konvertieren.
Dieser Hashwert wird jedoch als Wert für den Namen dieses Objekts verwendet. In Ihrem Fall,
{'gift' => {'name' => 'book', 'price' => 15.95 }}
Wenn Sie einen Hash benötigen, der im Objekt gespeichert ist, verwenden Sie as_json(root: false)
. Ich denke, dass root standardmäßig falsch ist. Weitere Informationen finden Sie im offiziellen Ruby-Handbuch
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
Sie können eine sehr elegante Lösung mit einem funktionalen Stil schreiben.
class Object
def hashify
Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }]
end
end
Konvertieren Sie Ihre Objekte rekursiv in Hash, indem Sie 'hashable' gem verwenden ( https://rubygems.org/gems/hashable ) Beispiel
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}}]}
Vielleicht möchten Sie instance_values
versuchen. Das hat bei mir funktioniert.
Sie sollten die inspect
-Methode Ihres Objekts überschreiben, um den gewünschten Hash zurückzugeben, oder einfach eine ähnliche Methode implementieren, ohne das Standardobjektverhalten zu überschreiben.
Wenn Sie schicker werden möchten, können Sie die Instanzvariablen eines Objekts mit object.instance_variables durchlaufen.
Erzeugt eine flache Kopie als Hashobjekt nur der Modellattribute
my_hash_gift = gift.attributes.dup
Überprüfen Sie den Typ des resultierenden Objekts
my_hash_gift.class
=> Hash
Gift.new.attributes.symbolize_keys
Ich habe angefangen, Strukturen zu verwenden, um Hash-Konvertierungen zu vereinfachen. Anstatt eine nackte Struktur zu verwenden, erstelle ich meine eigene Klasse, die von einem Hash abgeleitet ist. Auf diese Weise können Sie Ihre eigenen Funktionen erstellen und die Eigenschaften einer Klasse dokumentieren.
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}
Um dies ohne Rails zu tun, besteht eine saubere Möglichkeit darin, Attribute in einer Konstanten zu speichern.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
end
Um eine Instanz von Gift
in eine Hash
zu konvertieren, haben Sie folgende Möglichkeiten:
class Gift
...
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
Dies ist eine gute Möglichkeit, da nur das enthalten ist, was Sie in attr_accessor
definiert haben, und nicht jede Instanzvariable.
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}
Sie sollten Hashie ausprobieren, ein wunderbares Juwel: https://github.com/intridea/hashie
Wenn Sie auch verschachtelte Objekte konvertieren möchten.
# @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 # }}}