So I know of a few different approaches that I am aware of and I want explore the advantages and disadvantages of the various ways for various criteria which are:
Explicitly using the try method from active support
person.try(:pet).try(:name).try(:upcase)
Using a rescue nil
person.pet.name.upcase rescue nil
Using an && operator chain
person && person.pet && person.pet.name && person.pet.name.upcase
Monkey patching the Object class, see https://gist.github.com/thegrubbsian/3499234 for the original gist
class Object
def try_all(*methods)
values = [self]
methods.each do |method|
value = values.last.try(method)
return nil if value.nil?
values << value
end
values.last
end
end
person.try_all(:pet, :name, :upcase)
Don't have nil safe code, instead validate the data before you call the code
#not a good implementation by any means
def person_has_pet_with_name? person
begin
return true if !person.pet.name.nil?
rescue
return false
end
end
person.pet.name.upcase if person_has_pet_with_name?(person)
My personal opinion about monkey patching in general is do NOT do it unless there is no other way (and even than I think twice if I really want to monkey patch).
Besides Rails already bloated objects a lot. So I'd not suggest custom bloating objects even more.
Why not avoiding to break the law of Demeter by the classic delegator approach:
class Person
attr_accessor :pet
delegate :name_upcased, to: :pet,
prefix: true, allow_nil: true
end
class Pet
attr_accessor :name
def name_upcased
@name.upcase if @name
end
end
@person.try :pet_name_upcased
You can also read about the law of Demeter at Do not break the law of Demeter! and Module#delegate.
At least I would not stick to Object#try as long as a simple condition solves it, because looking at the source of 'try' it is more costly than the condition.
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