Reputation: 3794
I cannot seem to find a way to do this. All I want to do is try the first statement, if it is blank or null (at any stage) then return the other one. For instance
a.b.c.blank? ? a.b.c : 'Fill here'
This is causing me nil:NillClass
exception. Is there a way to fix this in a simple one liner way?
Upvotes: 0
Views: 2221
Reputation: 21
Since Ruby 2.3.0 (released 2015-12-25), this can be achieved using the save navigation operator
, which is similar to Groovy's and Kotlin's null safe ?
:
new method call syntax,
object&.foo', method foo is called on
object' if it is not nil.
# a as object { b: { c: 'foobar' } }
a&.b&.c&.empty? ? 'Fill here' : a.b.c #=> 'foobar'
nil&.b&.c&.empty? ? 'Fill here' : a.b.c #=> 'Fill here'
Safe calls return nil
when they're called upon nil objects. This is why the second case in the above example evaluates to nil
and thus false
.
source: NEWS for Ruby 2.3.0 (Feature #11537)
see also: What is the difference between try
and &.
(safe navigation operator) in Ruby
Upvotes: 0
Reputation: 14082
If you have active_support
available, you can use Object#try
:
a.try(:b).try(:c) or 'Fill here'
If you don't have that, it's pretty easy to monkey-patch Object
to add one. Here's the code in active_support
, just put it some where before you are using try
method.
class Object
def try(*a, &b)
if a.empty? && block_given?
yield self
else
public_send(*a, &b) if respond_to?(a.first)
end
end
end
After that, you can use it:
a = nil
a.try(:b).try(:c).try(:nil?) #=> true
b = 1
b.try(:+, 2) #=> 3
Upvotes: 2
Reputation: 106982
I would require the ActiveSupport package that allow the use of presence
do something like this:
require 'active_support'
require 'active_support/core_ext/object/blank'
a.presence && a.b.presence && a.b.c.presence || 'Fill here'
See: http://apidock.com/rails/Object/presence
Upvotes: 0
Reputation: 12719
There's not nil:NilClass
exception thrown by default.
a
or b
or c
may be nil, so for a one line statement you can do:
# require this to use present?, not needed with rails
require 'active_support/all'
a.present? ? (a.b.present? ? (a.b.c.present? ? a.b.c : 'Fill here') : 'Fill here') : 'Fill here'
(And this is ternary expression, not exactly an if statement)
But this is ugly, although you can remove parts of the expression if you are sure that a
or a.b
is never nil
.
I used present?
over blank?
to keep the same order as your expression. The ternary operator evaluates the first expression if the condition is true, so this may be your error.
Upvotes: 0