2011-02-17 79 views
102

比方说,我有一个Gift对象@name = "book" & @price = 15.95。将Ruby转换为Hash {name: "book", price: 15.95}的最好方法是什么?不是Rails(尽管也可以自由地给出Rails的答案)?红宝石将对象转换为哈希

+16

会@ gift.attributes.to_options吗? – 2011-02-17 15:02:09

+1

哦快照 - 伟大的ActiveRecord解决方案 – Dominic 2011-02-17 15:05:13

+0

1)礼物是一个ActiveRecord对象吗? 2)我们可以认为@ name/@价格不仅仅是实例变量,还有读者访问器? 3)你只想要名字,价格或礼物中的所有属性,无论它们是什么? – tokland 2011-02-17 16:25:51

回答

70
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

或者遍历一个对象的实例变量?

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 
+3

您可以使用inject来跳过初始化变量:gift.instance_variables.inject({}){| hash,var | hash [var.to_s.delete(“@”)] = gift.instance_variable_get(var); hash} – Jordan 2011-02-17 21:05:34

+7

不错。我用`var [1..- 1] .to_sym`替换`var.to_s.delete(“@”)`来获取符号。 – ma11hew28 2011-02-21 18:38:58

+3

不要使用注入,请使用`gift.instance_variables.each_with_object({}){| var,hash | hash [var.to_s.delete(“@”)] = gift.instance_variable_get(var)}`并去掉尾部的';哈希' – Narfanator 2013-06-10 00:14:08

4

您应该覆盖对象的inspect方法以返回所需的散列,或者只是实现类似的方法而不覆盖默认对象行为。

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} 
10
class Gift 
    def to_hash 
    instance_variables.map do |var| 
     [var[1..-1].to_sym, instance_variable_get(var)] 
    end.to_h 
    end 
end 
12

对于Active Record对象

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() 
30
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95} 
249

只要说(当前对象).attributes

.attributes返回任何objecthash。而且它也更干净。

3

递归转换你的对象使用散列“哈希的”宝石(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}}]} 
1

产生一个浅副本只是模型的哈希对象属性

my_hash_gift = gift.attributes.dup 

检查产生的物体的类型

my_hash_gift.class 
=> Hash 
5

您可以使用功能风格编写非常优雅的解决方案。如果您需要嵌套对象转换以及

JSON.parse(object.to_json) 
9

如果您不是在Rails环境(即没有ActiveRecord的可用),这可能是有帮助的。

# @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 # }}} 
0

class Object 
    def hashify 
    Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }] 
    end 
end 
3

可能想尝试instance_values。这对我有效。

3

您可以使用as_json方法。它会将你的对象转换为哈希。

但是,该散列将作为一个值作为该对象的名称作为一个键。在你的情况下,

{'gift' => {'name' => 'book', 'price' => 15.95 }} 

如果你需要一个存储在对象中的散列使用as_json(root: false)。我认为默认情况下root会是false。欲了解更多信息请参考官方红宝石引导

http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json

0

Gift.new.attributes.symbolize_keys