What is the difference between `try` and `&.` (saf

2020-02-09 00:48发布

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.

4条回答
爷的心禁止访问
2楼-- · 2020-02-09 01:02

The try method ignores a lot of things, it just gives it a shot and calls it a day if things don't work out.

The & conditional navigation option will only block calls on nil objects. Anything else is considered to be valid and will proceed with full consequences, exceptions included.

查看更多
劫难
3楼-- · 2020-02-09 01:10

agree with @Redithion in comment section

The Safe Navigation Operator (&.) in Ruby

Safe navigation operator returns nil if a method is called on a nil object. Before this, if a method is called on a nil object, it throws an error as given below.

$ nil.some_method
=> NoMethodError: undefined method 'some_method' for nil:NilClass

Why do we need safe navigation?

Many a times, we don’t get object because of some incorrect input values. In this case, if we proceed calling methods expecting as we have an object, the code might break if object comes up to be nil object.

To avoid such case, safe navigation is introduced. This makes sure that our code won’t break even if the object on which method is called is nil object. This should be used when we are good with receiving nil object when the method call fails.

Examples

Imagine you have an account that has an owner and you want to get the owner’s address. If you want to be safe and not risk a Nil error you would write something like the following.

if account && account.owner && account.owner.address 
... 
end

This is really verbose and annoying to type. ActiveSupport includes the try method which has a similar behaviour (but with few key differences that will be discussed later):

if account.try(:owner).try(:address)
...
end

It accomplishes the same thing - it either returns the address or nil if some value along the chain is nil. The first example may also return false if for example the owner is set to false.

Using &.

We can rewrite the previous example using the safe navigation operator:

account&.owner&.address
查看更多
来,给爷笑一个
4楼-- · 2020-02-09 01:11

I am arriving to the party a bit late here, the other answers have covered how it works, but I wanted to add something that the other answers have not covered.

Your question asks What is the difference between try and &. in Ruby. Ruby being the key word here.

The biggest difference is that try doesn't exist in Ruby, it is a method provided by Rails. you can see this or yourself if you do something like this in the rails console:

[1, 2, 3].try(:join, '-')
#=> "1-2-3" 

However if you do the same thing in the irb console, you will get:

[1, 2, 3].try(:join, '-')
NoMethodError: undefined method `try' for [1, 2, 3]:Array

The &. is part of the Ruby standard library, and is therefore available in any Ruby project, not just Rails.

查看更多
放我归山
5楼-- · 2020-02-09 01:14

&. 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 basically it saves you from calling a method on nil, but if an object is presented it will try to call its method as usual.

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.

查看更多
登录 后发表回答