What is the best practice for handling nil objects and properties?

Let's say I have a User object that has an email property, and I need the last top last line of their email :

 u = User.find(1) letter = u.email.upcase.last 

If u or email nil in this chain, I get a NoMethodError: undefined method 'blah' for nil:Nilclass . I have to work on it in most cases, but sometimes nil gets what he doesn't need or is hard to maintain. One way would be detailed:

 u = User.find(1) letter = nil if u && u.email letter = u.email.upcase.last end 

But it becomes annoying and dangerous in view or in a long chain of a.bunch.of.properties.down.a.hierarchy . I read about the try method in Rails:

 u = User.find(1) letter = u.try(:email).try(:upcase).try(:last) 

It's less verbose, but I feel bad writing all these attempts. And as soon as I put try in the chain, I have to use them to the end. Is there a better way?

+6
source share
4 answers

I like to use Null Object Pattern . Avdi has a great article explaining this , but the main idea is that you have a small class that can stand behind the object and intelligently respond to messages you can pass the original object. I found that they are useful not only to prevent NoMethodError , but also to set default / nice messages.

For example, you can do:

 class NilUser def email "(no email address)" end end u = User.find(1) || NilUser.new u.email.upcase.last # => No errors! 
+7
source
 User.find(1) 

An exception will be thrown if the user with id 1 does not exist, so you do not need to worry about him here

 u.email 

If you have in your model

 validates :email, presence: true 

You do not need to worry about nil, because a user without email cannot be in the database

But I think you are asking about a general way to handle nils in ruby ​​code. I have been using the Null Object pattern recently

http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/

http://robots.thoughtbot.com/post/20907555103/rails-refactoring-example-introduce-null-object

Rails: replacing try with a null object template

https://github.com/martinciu/nullobject

+1
source

I just wanted to update this thread with another option: now Ruby (since version 2.3) gives us a safe navigation operator, the &. syntax &. .

So:

u.email.upcase

It would be:

u.email&.upcase

Like the Rail try method, the whole chain will return nil if a NoMethodError occurs on nil .

+1
source

You can also display the search result.

 [User.find(1)].map{|u| (u != nil ? u.mail : "no mail")}[0] 
0
source

Source: https://habr.com/ru/post/956326/


All Articles