Shpigford
Shpigford

Reputation: 25328

Custom Ruby method not working on nil objects

I have the following customer Ruby method:

class Fixnum
  def utc_datetime
    Time.at(self).utc.to_datetime
  end
end

I would use it like so:

time = 1386592732
time.utc_datetime

The problem is when time is nil. When it's nil, it throws this:

NoMethodError: undefined method `utc_datetime' for nil:NilClass

How can I avoid the NoMethodError?

Another use case that makes it a bit harder to just call an if statement to check is it's sometimes used for things like this:

Article.create(account: 1, published_at: time.utc_datetime, title: 'Example')

Upvotes: 2

Views: 92

Answers (5)

SirDarius
SirDarius

Reputation: 42879

The correct solution is to test for variable nullity:

if !time.nil?
  time.utc_datetime
  # ...
end

But you could also use a begin/rescue block...

begin
  time.utc_datetime
  # ...
rescue NoMethodError => err
  # recovery code
end

Yet another approach is for utc_datetime to not be a method of Fixnum, so it will perform the check itself, eg:

def utc_datetime(time)
  if time.nil?
    nil # or whatever you need
  else
    Time.at(time).utc.to_datetime
  end
end

The worst, but funniest solution is to give nil a utc_datetime method:

def nil.utc_datetime
  # whatever
end

An even better solution is to ensure that the time variable always contains a Fixnum instance.
Give it a default value, and make sure only Fixnums are assigned to it during its lifetime.

Upvotes: 1

dotpao
dotpao

Reputation: 126

nil.to_i returns zero

convert time to integer before call utc_datetime

time.to_i.utc_datetime

Upvotes: 1

Billy Chan
Billy Chan

Reputation: 24815

Firstly, as the comments of vgoff and Dave, what you need to do is not to call it on nil object. There is nothing wrong with the method.

Secondly, in the context of Rails, doing such is wrong. You don't need to set creation time manually. The field created_at will be created automatially, and at UTC time.

What you only need to do it

article.created_at.to_datetime

Upvotes: 0

Javier Ramirez
Javier Ramirez

Reputation: 3988

time.try(:utc_datetime) will try to call the method for you and will return either the return value of the call or nil if it didn't exist.

Upvotes: 4

Dan Grahn
Dan Grahn

Reputation: 9394

How about this? Just check to see if the variable is valid.

time.utc_datetime if time

Upvotes: 1

Related Questions