Adler Santos
Adler Santos

Reputation: 405

Dynamically populate an object's attributes in Ruby, whose attribute names are the same as hash keys

I have the following hash:

row = {:id => 1, :name => "Altus Raizen", :email => "[email protected]"}

Now I have a Person Struct with the same attributes as the keys in row:

Person = Struct.new(:id, :name, :email)

I want to dynamically populate a Person object using the values in the row hash as follows:

person = Person.new
person.id = row[:id]
person.name = row[:name]
person.email = row[:email]

The code above works, but there must be a more elegant way of doing this, i.e. populating the attributes dynamically. How do I do this? (I have 9 attributes actually, so the code above become much longer and "uglier" by considering to set values to the other attributes such as phone, address, etc.).

Upvotes: 0

Views: 508

Answers (2)

steenslag
steenslag

Reputation: 80065

In ruby >= 1.9. you can do:

row = {:id => 1, :name => "Altus Raizen", :email => "[email protected]"}
Person = Struct.new(:id, :name, :email)

p person = Person.new(*row.values)
# => <struct Person id=1, name="Altus Raizen", email="[email protected]">

Which happens to work because everything is in the right order. More control gives values_at, which also works on older Rubies:

row = {:id => 1, :name => "Altus Raizen", :email => "[email protected]"}
Person = Struct.new(:id, :name, :email)
p person = Person.new(*row.values_at(:id, :name, :email))

Another option is OpenStruct:

require 'ostruct'
row = {:id => 1, :name => "Altus Raizen", :email => "[email protected]"}
person = OpenStruct.new(row)
p person  #=><OpenStruct id=1, name="Altus Raizen", email="[email protected]">
puts person.name #=> Altus Raizen

Upvotes: 2

toro2k
toro2k

Reputation: 19228

person = Person.new
row.each_pair { |key, value| person.send("#{key}=", value) }

Upvotes: 7

Related Questions