Rubyがオブジェクトをハッシュに変換する


127

&を持つGiftオブジェクトがある@name = "book"とし@price = 15.95ます。これを{name: "book", price: 15.95}RailsではなくRuby のハッシュに変換する最良の方法は何ですか(ただし、Railsにも回答を提供してください)。


16
@ gift.attributes.to_optionsはしますか?
Mr. L

1
1)ギフトはActiveRecordオブジェクトですか?2)@ name / @ priceはインスタンス変数だけでなく、リーダーアクセサーでもあると想定できますか?3)名前と価格のみ、またはすべての属性をギフトに含めたいですか?
tokland

@ tokland、1)いいえ、@ nashが定義したものGiftまったく同じですが、2)確かに、インスタンス変数はリーダーアクセサーを持つことができます。3)ギフトのすべての属性。
ma11hew28

OK。インスタンス変数/リーダーアクセスに関する質問は、外部アクセス(nash)または内部メソッド(levinalex)が必要かどうかを知ることでした。「インサイド」アプローチの回答を更新しました。
tokland

回答:


80
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}

3
インジェクトを使用して、変数の初期化をスキップできます。gift.instance_variables.inject({}){| hash、var | hash [var.to_s.delete( "@")] = gift.instance_variable_get(var); ハッシュ}
ジョーダン

8
いいね。に置き換えvar.to_s.delete("@")var[1..-1].to_symシンボルを取得します。
ma11hew28

3
注入を使用しないでください、使用gift.instance_variables.each_with_object({}) { |var,hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }して、末尾を; hash
削除します

1
私はルビーのフェチを決して理解しませんeachmapそして、injectはるかに強力です。これは、Rubyで私が持っている1つの設計品質で mapありinject、で実装されていeachます。それは単に悪いコンピュータサイエンスです。
Nate Symer 2015

やや簡潔:hash = Hash[gift.instance_variables.map { |var| [var.to_s[1..-1], gift.instance_variable_get(var)] } ]
Marvin

293

(現在のオブジェクト)と言うだけです .attributes

.attributeshash任意のを返しますobject。そして、それもはるかにきれいです。


138
これは、Rubyメソッドではなく、ActiveModel固有のメソッドであることに注意してください。
ブリック


instance_values同様の出力のすべてのルビーオブジェクトに使用できます。
bishal

48

実装し#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

技術的には#はクラスメソッドを示すため、.to_hashである必要があります。
カレブ2015

6
実は違う。RDocドキュメントは言う:(Use :: for describing class methods, # for describing instance methods, and use . for example codeソース:ruby-doc.org/documentation-guidelines.html)また、公式ドキュメント(ruby CHANGELOG、github.com / ruby / ruby​​ / blob / v2_1_0 / NEWSなど)は#インスタンスメソッドとドットを使用しますクラスメソッドの場合はかなり一貫しています。
levinalex

このアンチパターンの代わりにインジェクトを使用してください。
YoTengoUnLCD 2017年

を使用したワンライナーバリアントeach_with_objectinstance_variables.each_with_object(Hash.new(0)) { |element, hash| hash["#{element}".delete("@").to_sym] = instance_variable_get(element) }
anothermh 2017年

43
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}

10
これはRailsですが、Ruby自体にはありませんinstance_values。MattがRubyの方法を要求したことに注意してください。具体的にはRailsではありません。
Christopher Creutzig 2012年

28
彼はまた、Railsにも回答を自由に与えることができると感じました...だから私はそうしました。
Erik Reedstrom、2012年

神はここで両方のバージョンを参照してください;)気に入った
セバスチャンシューマン

17

as_jsonメソッドを使用できます。オブジェクトをハッシュに変換します。

しかし、そのハッシュは、そのオブジェクトの名前をキーとする値になります。あなたの場合、

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

オブジェクトに保存されているハッシュが必要な場合は、を使用してくださいas_json(root: false)。デフォルトではrootはfalseになると思います。詳細については、公式のrubyガイドを参照してください

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


13

アクティブレコードオブジェクトの場合

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() 

2
面白いことに、それはRailsフレームワークの一部ではありません。そこにあると便利なようです。
Magne、

attributesメソッドはinの値を持つ新しいハッシュを返すため、to_hashメソッドで別のハッシュを作成する必要はありません。このように:attribute_names.each_with_object({}){| name、attrs | attrs [name] = read_attribute(name)}。ここを参照してください: github.com/rails/rails/blob/master/activerecord/lib/...
クリス・アキンプトン

あなたはマップでこれを行うことができました、あなたの副作用の実装は私の心の人を傷つけています!
Nate Symer 2016年


11
class Gift
  def to_hash
    instance_variables.map do |var|
      [var[1..-1].to_sym, instance_variable_get(var)]
    end.to_h
  end
end

6

関数スタイルを使用して、非常にエレガントなソリューションを作成できます。

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

4

inspectオブジェクトのメソッドをオーバーライドして目的のハッシュを返すか、デフォルトのオブジェクトの動作をオーバーライドせずに同様のメソッドを実装する必要があります。

より洗練されたものにしたい場合は、object.instance_variablesを使用してオブジェクトのインスタンス変数を反復できます。


4

'hashable' gem(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}}]}

4

試したいかもしれませんinstance_values。それでうまくいきました。


1

モデル属性のみのハッシュオブジェクトとして浅いコピーを生成します

my_hash_gift = gift.attributes.dup

結果のオブジェクトのタイプを確認します

my_hash_gift.class
=> Hash

0

ネストされたオブジェクトも変換する必要がある場合。

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

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}

0

ハッシュ変換を簡単にするために構造体を使い始めました。裸の構造体を使用する代わりに、ハッシュから派生した独自のクラスを作成します。これにより、独自の関数を作成でき、クラスのプロパティをドキュメント化します。

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}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.