web-dev-qa-db-fra.com

Ruby convertit l'objet en hachage

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

111
ma11hew28
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}
76
Vasiliy Ermolovich

Il suffit de dire (objet actuel) .attributes

.attributes renvoie une hash de toute object. Et c'est beaucoup plus propre aussi.

275
Austin Marusco

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
45
levinalex
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}
37
Erik Reedstrom

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() 
13
monika mevenkamp
class Gift
  def to_hash
    instance_variables.map do |var|
      [var[1..-1].to_sym, instance_variable_get(var)]
    end.to_h
  end
end
11
tokland

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 )
10
Andreas Rayo Kniep

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

10
vicke4

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
6
Nate Symer

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}}]}
4
mustafaturan

Peut-être envie d'essayer instance_values. Cela a fonctionné pour moi.

4
Hunter

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

4
Dominic

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
1
Sean

Gift.new.attributes.symbolize_keys

0
Lalit Kumar

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}
0
Alex

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}
0
Vini Brasil

Vous devriez essayer Hashie, un joyau merveilleux: https://github.com/intridea/hashie

0
andoke

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