I wanted to show a link in a Rails application based on whether a person was
The code looked something like this:
= link_to "Admin Menu", root_path if current_user.admin? && signed_in?
That would work when I was signed in but as soon as I signed out, I’d get a no method error.
That happens because when you’re signed out, there is no
To fix this issue, I wrote a more verbose statement:
- if signed_in? - if current_user.admin? = link_to "Admin Menu", root_path</pre>
I first checked whether a user was
signed_in?. If they were, then the
current_user would be available and I could use it.
It works but we can shorten this code by understanding how the ruby
&& operand is evaluated.
&& operand goes through conditions in order. As soon as it receives a
false, it returns
I had problems when evaluating the line below because
current_user didn’t exist and Ruby raised an error.
# No method error current_user.admin? && signed_in?
However, when I switched the order of these two statements, the error went away.
# works perfectly signed_in? && current_user.admin?
This works because the method
signed_in? will always return a true or false, regardless of whether we’re signed in or not.
signed_in? is true, Ruby continues to evaluate the second statement
signed_in? is false, Ruby doesn’t even look at
current_user.admin? and simply returns false. This is why the line below works:
= link_to "Admin Menu", root_path if signed_in? && current_user.admin?
Safe navigation operator and try
Another alternative is to use the safe navigation operator. If
current_user doesn’t exist, you can ask Ruby to fail silently with a nil instead of a no method error.
You can call the
try method and pass in the method you’re checking. If it doesn’t exist, Ruby will return nil instead of an error.
In Ruby 2.3, you can use the shorthand safe navigation operator
&. Behind the scenes,
& invokes the
current_user.blah? # No Method Error current_user.try(:blah) #nil current_user&.blah #nil
You can also daisy chain
current_user.try(:blah).try(:fake_method) #nil # or use the safe navigation operator current_user&.blah&.fake_method #nil