Reputation: 167
I have an object Foo
and want to assign multiple attributes to it at once, similar to assign_attributes
in Rails:
class Foo
attr_accessor :a, :b, :c
end
f = Foo.new
my_hash = {a: "foo", b: "bar", c: "baz"}
f.assign_attributes(my_hash)
The above does not work except if the class is an ActiveRecord Model in Rails. Is there any way to do it in Ruby?
Upvotes: 2
Views: 1452
Reputation: 114208
You can implement the mass-assignment method yourself.
One option is to set the corresponding instance variables via instance_variable_set
:
class Foo
attr_accessor :a, :b, :c
def assign_attributes(attrs)
attrs.each_pair do |attr, value|
instance_variable_set("@#{attr}", value)
end
end
end
Note that this will by-pass any custom setters. As said in the docs:
This may circumvent the encapsulation intended by the author of the class, so it should be used with care.
Another way is to dynamically invoke the setters via public_send
:
def assign_attributes(attrs)
attrs.each_pair do |attr, value|
public_send("#{attr}=", value)
end
end
This is equivalent to setting each single attribute sequentially. If a setter has been (re)defined to include constraints and controls on the value being set, the latter approach respects that.
It also raises an exception if you try to set undefined attributes: (because the corresponding setter doesn't exist)
f = Foo.new
f.assign_attributes(d: 'qux')
#=> NoMehodError: undefined method `d=' for #<Foo:0x00007fbb76038430>
In addition, you might want to ensure that the passed argument is indeed a hash and maybe raise a custom exception if the provided attributes are invalid / unknown.
Upvotes: 7
Reputation: 1424
The assign_attributes
is an instance method of ActiveRecord
You have to define your assign_attributes
method if not using ActiveRecord
def assign_attributes(attrs_hash)
attrs_hash.each do |k, v|
self.instance_variable_set("@#{k}", v)
end
end
Upvotes: 0