I have a data object that contains dozens of attr_accessor fields for various inputs. Can I somehow define the class so that all setters for all fields will e.g. set the value as an empty string instead of the attempted nil?
Here's a little module to do it:
module NilToBlankAttrAccessor
def nil_to_blank_attr_accessor(attr)
attr_reader attr
define_method "#{attr}=" do |value|
value = '' if value.nil?
instance_variable_set "@#{attr}", value
end
end
end
Just mix it in:
class Foo
extend NilToBlankAttrAccessor
nil_to_blank_attr_accessor :bar
end
And use it:
foo = Foo.new
foo.bar = nil
p foo.bar # => ""
foo.bar = 'abc'
p foo.bar # => "abc"
How it works
NilToBlankAttrAccessor#nil_to_blank_attr_accessor
first defines the attr_reader normally:
attr_reader attr
Then it defines the writer by defining a method with the same name as the accessor, only with an "=" at the end. So, for attribute :bar
, the method is named bar=
define_method "#{attr}=" do |value|
...
end
Now it needs to set the variable. First it turns nil into an empty string:
value = '' if value.nil?
Then use instance_variable_set, which does an instance variable assignment where the instance variable isn't known until runtime.
instance_variable_set "@#{attr}", value
Class Foo needs nil_to_blank_attr_accessor to be a class method, not an instance method, so it uses extend
instead of include
:
class Foo
extend NilToBlankAttrAccessor
...
end
Instead of doing
object.foo = given_input
you should do
object.foo = given_input.nil? ? "" : given_input
or if you want to turn false
into ""
as well, then
object.foo = given_input || ""
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With