Скажем, у меня есть объект Gift
с @name = "book"
и @price = 15.95
. Какой лучший способ преобразовать это в Hash {name: "book", price: 15.95}
в Ruby, а не Rails (хотя не стесняйтесь также дать ответ Rails)?
Ruby конвертирует Object в Hash
Ответ 1
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}
Альтернативно с 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}
Ответ 2
Просто скажите (текущий объект) .attributes
.attributes
возвращает a hash
любого object
. И это намного чище.
Ответ 3
Реализовать #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
Ответ 4
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}
Ответ 5
Вы можете использовать метод as_json
. Это преобразует ваш объект в хеш.
Но этот хэш придет в качестве значения имени этого объекта в качестве ключа. В твоем случае,
{'gift' => {'name' => 'book', 'price' => 15.95 }}
Если вам нужен хеш, который хранится в объекте, используйте as_json(root: false)
. Я думаю, что по умолчанию root будет ложным. Для получения дополнительной информации обратитесь к официальному руководству рубин
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
Ответ 6
Для активных объектов записи
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
а затем просто вызовите
gift.to_hash()
purch.to_hash()
Ответ 7
class Gift
def to_hash
instance_variables.map do |var|
[var[1..-1].to_sym, instance_variable_get(var)]
end.to_h
end
end
Ответ 8
Если вы не находитесь в среде Rails (т.е. не имеете ActiveRecord), это может быть полезно:
JSON.parse( object.to_json )
Ответ 9
Вы можете написать очень элегантное решение, используя функциональный стиль.
class Object
def hashify
Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }]
end
end
Ответ 10
Вы должны переопределить метод inspect
вашего объекта, чтобы вернуть желаемый хеш, или просто реализовать аналогичный метод без переопределения поведения объекта по умолчанию.
Если вы хотите получить fancier, вы можете перебирать переменные экземпляра объекта с помощью object.instance_variables
Ответ 11
Рекурсивно конвертировать ваши объекты в хеш с помощью драгоценного камня "hashable" (https://rubygems.org/gems/hashable) Пример
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}}]}
Ответ 12
Можете попробовать instance_values
. Это сработало для меня.
Ответ 13
Производит мелкую копию как хэш-объект только атрибутов модели
my_hash_gift = gift.attributes.dup
Проверьте тип результирующего объекта
my_hash_gift.class
=> Hash
Ответ 14
Вы должны попробовать Hashie, замечательный камень: https://github.com/intridea/hashie
Ответ 15
Если вам нужны также вложенные объекты.
# @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 # }}}
Ответ 16
Gift.new.attributes.symbolize_keys
Ответ 17
Чтобы сделать это без Rails, чистый способ - хранить атрибуты на константе.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
end
А затем, чтобы преобразовать экземпляр Gift
в Hash
, вы можете:
class Gift
...
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
Это хороший способ сделать это, потому что он будет включать в себя только то, что вы определили в attr_accessor
, а не каждую переменную экземпляра.
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}
Ответ 18
Я начал использовать структуры для упрощения хеширования. Вместо использования простой структуры я создаю свой собственный класс, производный от хеша, это позволяет вам создавать свои собственные функции и документировать свойства класса.
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}