ruby-on-railsrubyif-statementnomethoderrorgrape-api

What is the difference between `try` and `&.` (safe navigation operator) in Ruby


Here is my code:

class Order < Grape::Entity
  expose :id { |order, options| order.id.obfuscate }
  expose :time_left_to_review do |order, options|
    byebug
    order&.time_left_to_review # ERROR
  end
  expose :created_at { |order, options| order.last_transition.created_at }
end

# NoMethodError Exception: undefined method `time_left_to_review' for #<Order:0x007f83b9efc970>

I thought &. is a shortcut for .try but I guess I was wrong. May someone point me to the right direction regarding what I am missing?

I feel like it's not ruby related. Grape maybe? Though I don't get how it could be.


Solution

  • &. works like #try!, not #try.

    And here is description of #try! (from documentation):

    Same as #try, but will raise a NoMethodError exception if the receiving is not nil and does not implemented the tried method.

    So, &. saves you from calling a method on nil, but if the object is present it will try to call the method as usual, including raising NoMethodError if the method is not implemented.

    #try, on the other hand, saves you from calling a method on nil and calling a method that is not implemented. It will return nil in either case, and never raise NoMethodError.

    The quote is from Rails Documentation, and so it's important to emphasize that Ruby does not provide #try; it's provided by Rails, or more accurately ActiveSupport. The safe navigation operator (&.) however, is a language feature presented in Ruby 2.3.0.