How should I write:
if @parent.child.grand_child.attribute.present?
do_something
without cumbersome nil checkings to avoid exception:
I suppose you can do it using a delegate
method as a result you'll have sth like
@parent.child_grand_child_attribute.present?
Rails has object.try(:method)
:
if @parent.try(:child).try(:grand_child).try(:attribute).present?
do_something
http://api.rubyonrails.org/classes/Object.html#method-i-try
All these answers are old, so I thought I should share more modern options.
If you are getting an association that might not exist:
@parent&.child&.grand_child&.attribute
if you are reaching into a hash for a key that might not exist:
hash = {
parent_key: {
some_other_key: 'a value of some sort'
},
different_parent_key: {
child_key: {
grand_child: {
attribute: 'thing'
}
}
}
}
hash.dig(:parent_key, :child_key, :grandchild_key)
Either of these will gracefully return nil if child, grandchild, or attribute don't exist
For fun, you could use a fold:
[:child, :grandchild, :attribute].reduce(@parent){|mem,x| mem = mem.nil? ? mem : mem.send(x) }
but using andand is probably better, or ick, which I like a lot and has methods like try
and maybe
.
You can slightly reduce it by assigning the intermediate values to some local variable:
if a = @parent.child and a = a.grandchild and a.attribute
You coult just catch the exception:
begin
do something with parent.child.grand_child.attribute
rescue NoMethodError => e
do something else
end