Ruby when nil or empty string - ruby-on-rails

I have RoR app, and I want to change some lines of my code to be more elegant.
foo = params[:customer][:language].nil? or params[:customer][:language].empty? ? 'es' : params[:customer][:language]
I try with
foo = params[:customer][:language] || 'es'
But it's not the same exactly.
Thanks in advance.

You can use activesupport's Object#presence method, like this:
foo = params[:customer][:language].presence || 'es'

Related

Camelize up to a certain part of a string

I have:
s = "like_so__case"
camelize gives this:
s.camelize # => "LikeSoCase"
I'm looking for conversion up to a double underscore __ to get:
"LikeSo__case"
How can I camelize only up to a certain part of a string?
The simplest option is to gsub part of your string.
'like_so__case'.gsub(/(.*?)(__.*)/) { "#{$1.camelize}#{$2}" }
#=> "LikeSo__case"
UPDATE
Cleaner and faster way arising from comments.
'like_so__case__h'.sub(/(.*?)(?=__)/, &:camelize)
#=> "LikeSo__case__h"
s = "like_so__case"
=> "like_so__case"
s.split('__', 2).tap { |s| s[0] = s[0].camelize }.join('__')
=> "LikeSo__case"
You of course could wrap it in string method
For getting this LikeSo__case, we can do like:
s="like_so__case"
s.split('__').tap { |s| s[0] = s[0].camelize }.join('__')
Your description on the demand is not so clear.
From your excepted result, I understand it as 'camelize a part of string until a pattern'. I should note one thing first that camelize is not part of Ruby's standard library of class String. ActiveSupport::Inflector provides it.
So if you want to just camelize each part divided by a pattern, use str.split('_').map(&:capitalize).join('_'). In your case, it returns 'Like_So__Case'.
Ruby's String has another instance method named partition, which splits the string into three parts (an array):
Part before the pattern
The pattern
Part after the pattern
So str.partition('__').tap { |a| a[0] = a[0].split('_').map(&:capitalize).join }.join should be your answer in plain Ruby.
No need of relying on camelize. Simply, this:
"like_so__case"
.gsub(/_?([a-z])([a-z]*)(?=.*__)/i){$1.upcase + $2.downcase}
# => "LikeSo__case"
def camelize(s)
for i in 0..s.size-2 do
if s[i] == "_" and s[i+1] == "_"
next
elsif s[i] == "_" and s[i+1] != "_" and s[i-1] != "_"
s[i+1] = s[i+1].upcase
s[i] = ""
else
next
end
end
return s
end
Use this method to solve your problem
s = "like_so__case"
i = s.index('__')
#=> 7
s.tap { |s| s[0,i] = s[0,i].camelize }
#=> LikeSo__case
The last line could be replaced by two lines:
s[0,i] = s[0,i].camelize
s
If the original string is not to be mutated write
s.dup.tap { |s| s[0,i] = s[0,i].camelize }

Why is rails throwing error if I don't execute code on nil

I need to check if a property is nil and if it isn't, get the content
tmp[:field] = maybe_nil != nil ? maybe_nil.content : ''
If it is nil, display blank string.
Why would I get undefined method 'content' for nil:NilClass if I'm checking for nil and skipping the content accessor on purpose? How else would I execute this logic?
Thanks!
tmp[:field] = maybe_nil ? maybe_nil.content : ''
Unless something extraordinary is the case, this should work
tmp[:field] = maybe_nil.nil? ? "" : maybe_nil.content
if maybe_nil.content should always return a string I would do as below instead:
tmp[:field] = maybe_nil.try(:content).to_s
nil.to_s #=> ""
tmp[:field] = maybe_nil.present? ? maybe_nil.content : ''
Just do this
tmp[:field] = maybe_nil.try(:presence).try(:content) || ''

Easier way to write If hash includes then - Ruby

I have the following in an initialize method on my model:
#home_phone = contact_hash.fetch('HomePhone')
However, sometimes I need this instead:
#home_phone = contact_hash.fetch('number')
Also, sometimes neither of those will be true and I will need the home_phone attribute to be empty.
How can I write this out without creating a big loop like so:
if contact_hash.has_key?('HomePhone')
#home_phone = contact_hash.fetch('HomePhone')
elsif contact_hash.has_key?('number')
#home_phone = contact_hash.fetch('number')
else
#home_phone = ""
end
You could try
#home_phone = contact_hash.fetch('HomePhone', contact_hash.fetch('number', ""))
or better
#home_phone = contact_hash['HomePhone'] || contact_hash['number'] || ""
contact_hash.values_at('HomePhone','number','home_phone').compact.first
Edit:
My first solution did not really give the answer asked for. Here is a modified version, although I think in the case of only 3 options the solution given by #knut is better.
contact_hash.values_at('HomePhone','number').push('').compact.first
def doit(h, *args)
args.each {|a| return h[a] if h[a]}
""
end
contact_hash = {'Almost HomePhone'=>1, 'number'=>7}
doit(contact_hash, 'HomePhone', 'number') # => 7
You could use values_at I suppose:
#home_phone = contact_hash.values_at('HomePhone', 'number').find(&:present?).to_s
That isn't exactly shorter but it wouldn't be convenient if you had the keys in an array:
try_these = %w[HomePhone number]
#home_phone = contact_hash.values_at(*try_these).find(&:present?).to_s
You could also wrap that up in a utility method somewhere or patch it into Hash.

Ruby On Rails: Concatenate String in loop

I am new to RoR. I was trying to find a way over googling to concatenate the string in a loop in Controller.
assets = Asset.where({ :current_status => ["active"] }).all
assets.each do |a|
string = string + ":"+ a.movie_title
end
I want to concatenate attribute "movie_title" as a string that would be colon separated.
but i get error
undefined method `+' for nil:NilClass
The easiest way is probably:
string = assets.collect(&:movie_title).join(':')
collect(&:movie_title) is the same as collect { |asset| asset.movie_title }, which returns an Array of the movie titles. join(':') creates a String with the values from the Array separated by :.
Try this
assets = Asset.where({ :current_status => ["active"] }).all
string = ""
if assets.present?
assets.each do |a|
string = string + ":"+ a.movie_title
end
end
Why not just this:
"#{string} : #{a.movie_title}"
If they are nil you will get " : "
Methods join (docs) and map (docs) may help you.
Try following:
assets = Asset.where(current_status: ["active"]).all
assets.map(&:movie_title).join(':')

Ruby/Rails using || to determine value, using an empty string instead of a nil value

I usually do
value = input || "default"
so if input = nil
value = "default"
But how can I do this so instead of nil It also counts an empty string '' as nil
I want so that if I do
input = ''
value = input || "default"
=> "default"
Is there a simple elegant way to do this without if?
Rails adds presence method to all object that does exactly what you want
input = ''
value = input.presence || "default"
=> "default"
input = 'value'
value = input.presence || "default"
=> "value"
input = nil
value = input.presence || "default"
=> "default"
I usually do in this way:
value = input.blank? ? "default" : input
In response to the case that input might not be defined, you may guard it by:
value = input || (input.blank? ? "default" : input)
# I just tried that the parentheses are required, or else its return is incorrect
For pure ruby (not depending on Rails), you may use empty? like this:
value = input || (input.empty? ? "default" : input)
or like this (thanks #substantial for providing this):
value = (input ||= "").empty? ? "default" : input
Maybe irrelavant but I would use highline like this:
require "highline/import"
input = ask('Input: ') { |q| q.default = "default" }
It works without Rails. Really neat solution.

Resources