Hopstream
Hopstream

Reputation: 6451

Perform map only when not nil?

The following breaks if names is nil. How can I have this map execute only if it's not nil?

self.topics = names.split(",").map do |n|
  Topic.where(name: n.strip).first_or_create!
end

Upvotes: 6

Views: 9663

Answers (6)

woto
woto

Reputation: 3077

Finally in ruby 2.7 you can use

['Moscow', 'Norilsk'].map do |city|
  city if city == 'Norilsk'
end
=> [nil, "Norilsk"]

['Moscow', 'Norilsk'].filter_map do |city|
  city if city == 'Norilsk'
end
=> ["Norilsk"]

Upvotes: 0

Chris Kerlin
Chris Kerlin

Reputation: 140

nil.to_s is "", so try

names.to_s.split(",").map

Upvotes: 1

ndnenkov
ndnenkov

Reputation: 36110

From ruby 2.3.0 onward, you can use the safe navigation operator (&.):

self.topics = names&.split(",").map do |n|
  Topic.where(name: n.strip).first_or_create!
end

Upvotes: 0

the Tin Man
the Tin Man

Reputation: 160611

I think the real problem is you're not checking to see if it's safe to perform the action, and then have to scramble to try to recover when it's not safe.

Instead, check to see if names is valid before you try to split it. You don't say what self.topics should be if names is nil, but I'd start with something like:

self.topics = if names.nil?
                # whatever self.topic should be if names == nil
              else
                names.split(",").map do |n|
                  Topic.where(name: n.strip).first_or_create!
                end
              end

Upvotes: 0

vee
vee

Reputation: 38645

A couple of other options:

Option 1 (checking for result of split when executing map on it):

names_list = names.try(:split, ",")
self.topics = names_list.map do |n|
    Topic.where(name: n.strip).first_or_create!
end if names_list

Option 2 (using try, which will prevent the error):

self.topics = names.try(:split, ",").try(:map) do |n|
    Topic.where(name: n.strip).first_or_create!
end

Upvotes: 8

PinnyM
PinnyM

Reputation: 35531

That depends on what you want topics to become if names is actually nil. The most elegant solution would probably be to substitute an empty string where names is nil:

self.topics = (names || '').split(",").map do |n|
...

But that would assign an empty array to topics. If that's not what you want, you can wrap this with a nil check like this:

if names
  self.topics = ...
end

Or like this:

self.topics = names.split(",").map do |n|
  ...
end if names

Upvotes: 1

Related Questions