Rails method to detect array of empty strings (["", "",...]) as empty - ruby-on-rails

Is there a rails function to detect ["", "", ...] (i.e. An array containing only empty string or strings) as empty
My requirement:
[""].foo? => true
["", ""].foo? => true
["lorem"].foo? => false
["", "ipsum"].foo? => false
I tried using array.reject!(&:empty?).blank?. It worked, but this changed my array. I don't want my array to be changed. Please help me find a compact method.

There isn't a single method, but you can use .all?.
["", nil].all?(&:blank?) # => true
["ipsum", ""].all?(&:blank?) # => false
Or you can get the opposite result with .any?.
["", nil].any?(&:present?) # => false
["lorem", ""].any?(&:present?) # => true

OP was asking for a solution for Rails but I came here while looking for a generic Ruby solutions. Since present? and blank? are both Rails extensions the above solution did not work for me (unless I pull in ActiveSupport which I didn't want).
May I instead offer a simpler solution:
[nil, nil].join.empty? # => true
["", nil].join.empty? # => true
["lorem", nil].join.empty? # => false

Related

Is there a benefit to Rails' ".present?" method?

In Ruby on Rails, is there a difference between:
if obj
# ...
end
and:
if obj.present?
# ...
end
It seems they do the same thing and not using .present? would help keep the line of code shorter and potentially cleaner. I understand that .present? is the opposite of blank? but should we always be using it when trying to determine if an object is "truthy" or not?
Is there a performance difference of some kind?
The #present? method does a bit more in that it also returns false if the string was a real but empty string (i.e. "")
Which is useful as your forms might return empty strings instead of nils.
You can also use #presence which is a useful way of returning the value only if the value is #present?
name = params[:name].presence || 'ardavis'
The above wouldn't work if params[:name] was an empty string and you didn't use #presence
They don't do the same thing at all.
In Ruby everything except nil and false are truthy. This is amazingly sane compared to the type casting schenigans in other popular dynamic languages.
irb(main):003:0> !!""
(irb):3: warning: string literal in condition
=> true
irb(main):004:0> !!0
=> true
irb(main):005:0> !![]
=> true
irb(main):006:0> !!{}
=> true
irb(main):007:0> !!Object.new
=> true
irb(main):008:0> !!nil
=> false
irb(main):009:0> !!false
=> false
present? and presence are a part of ActiveSupport which can be used to test for nil and false but are actually more useful when dealing with user input:
irb(main):010:0> "".present?
=> false
irb(main):011:0> [].present?
=> false
irb(main):012:0> {}.present?
=> false
present? and presence are widely overused by Rails beginners that don't bother to learn Ruby first. Just use implicit truth checks (if foo) or foo.nil? if you just want to check if an argument is sent or not or if a variable is set.
And while .present? can be used on ActiveRecord collections but there are more idiomatically correct choices such as any? and none?.
If you are working with string only checking if the attribute or object exists will return true, but present method will return false.
Here are some examples:
# Double negation return the boolean value
!!""
=> true
"".present?
=> false
" ".present?
=> false
[].present?
=> false
nil.present?
=> false
true.present?
=> true
false.present?
=> false
{}.present?
=> false
person = {:firstName => "John", :lastName => "Doe"}
person.present?
=> true
5.present?
=> true

How to check there is only one object inside the ruby variable?

I have a ruby variable #object which can have only one object inside it or multiple objects.
How to check that in Rails.
Tried checking with
.length
.size
.count
Michael's answer should work already, but another option is to check if it includes the Enumerable module (should support all "Array"-ish objects, unless they have their own custom implementation):
#object.is_a? Enumerable
# => returns true if Array-ish or false
Examples
# Array
[].is_a? Enumerable
# => true
# Hash
{}.is_a? Enumerable
# => true
# Set
[].to_set.is_a? Enumerable
# => true
# Subclass of any of the above
class MyArr < Array
end
MyArr.new.is_a? Enumerable
# => true
# ActiveRecord::Relation
User.all.is_a? Enumerable
# => true
# String
'somestring'.is_a? Enumerable
# => false
# Integer/Float
123.is_a? Enumerable
# => false
(123.45).is_a? Enumerable
# => false
# Time
Time.now.is_a? Enumerable
# => false
Gotcha
## Rails 4:
ActionController::Parameters.new.is_a? Enumerable
# => true
## Rails 5:
ActionController::Parameters.new.is_a? Enumerable
# => false
# in Rails 5, ActionController::Parameters no longer inherits from Hash
# ActionController::Parameters is the type of the variable `params` in your controllers
# Because practically speaking you can loop over it, so it should still be an "Array"
# Therefore, you might want to use the following instead of `.is_a? Enumerable`
#object.respond_to? :each
# => returns true if Array-ish or false
ActionController::Parameters.new.respond_to? :each
# => true
You can use respond_to? method
#object.respond_to? :size
It returns true if array of objects

Rails 4 to 5 AR boolean deprecation

I have a model wish contains the bellow method called by before_validation :
def set_to_false
self.confirme ||= false
self.deny ||= false
self.favoris ||= false
self.code_valid ||= false
end
When I run my tests, I got the deprecation message
DEPRECATION WARNING: You attempted to assign a value which is not
explicitly true or false to a boolean column. Currently this value
casts to false. This will change to match Ruby's semantics, and will
cast to true in Rails 5. If you would like to maintain the current
behavior, you should explicitly handle the values you would like cast
to false. (called from cast_value at
./Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.2.1/lib/active_record/type/boolean.rb:17)
I understand I have to cast but I couldn't find a simple and smart way to do it. Any help to remove this deprecation would be great.
Here's a simple booleanification trick that I use often, double negation:
before_validation :booleanify
def booleanify
self.confirm = !!confirm
self.deny = !!deny
...
end
In case you are not familiar with this trick, it'll convert all values to their boolean equivalents, according to ruby rules (nil and false become false, everything else becomes true)
'foo' # => "foo"
!'foo' # => false
!!'foo' # => true
!nil # => true
!!nil # => false

Rails console compare model instances

Is there a way to compare two instances of model like
Model.compare_by_name("model1", "model2") which would list the differing column fields
You can use ActiveRecord::Diff if you want a mapping of all the fields that differ and their values.
alice = User.create(:name => 'alice', :email_address => 'alice#example.org')
bob = User.create(:name => 'bob', :email_address => 'bob#example.org')
alice.diff?(bob) # => true
alice.diff(bob) # => {:name => ['alice', 'bob'], :email_address => ['alice#example.org', 'bob#example.org']}
alice.diff({:name => 'eve'}) # => {:name => ['alice', 'eve']}
There is no standard comparator for this. The standard ActiveModel comparator:
Returns true if comparison_object is the same exact object, or comparison_object is of the same type and self has an ID and it is equal to comparison_object.id.
You can write your own by using Hash#diff from activesupport. Something like the following should hopefully get you started:
def Model.compare_by_name(model1, model2)
find_by_name(model1).attributes.diff(find_by_name(model2).attributes)
end
Without using a library or defining a custom method, you can easily get a diff between two models.
For instance,
a = Foo.first
b = Foo.second
a.attributes = b.attributes
a.changes #=> {"id" => [1,2] }

How to check if object belongs to an array in Ruby

I usually have to check things like:
if ['Bob','Mary','John'].include? #user.name
Is there a way to write something like:
if #user.name.in? ['Bob','Mary','John']
Thank you.
Rails 3.1 has got this Object.in? method
characters = ["Konata", "Kagami", "Tsukasa"]
"Konata".in?(characters) # => true
character = "Konata"
character.in?("Konata", "Kagami", "Tsukasa") # => true
If #user.name is a String, you can add in? to String.
class String
def in? a
a.include? self
end
end
This has the following effect:
irb(main):011:0> 'Bob'.in? ['Bob','Mary','John']
=> true
irb(main):012:0> 'Jane'.in? ['Bob','Mary','John']
=> false

Resources