I have an object with a boolean var.
field :processing, :type => Boolean
The dev before me wrote some code that says this.
:processing => nil
(He is, for some reason, setting it to nil instead of false.)
He then does this if statement
return if self.processing
dosomethingelse....
If I write code that does this
:processing => false
what happens the next time this code runs? Does dosomethingelse run?
return if self.processing
dosomethingelse....
UPDATE ===========
To many questions below so will answer here.
I added this
field :processing, :type => Boolean, :default => false
and it broke the app. When I changed to the above dosomethingelse never gets run?
return if self.processing returns. Any suggestions?
UPDATE 2 =======================================
Here is every reference to processing in my code (redacted). Also I am using MongoDB if that matters.
.where(:processing => nil).gt(:retries => 0).asc(:send_time).all.entries
if self.processing
end
return if self.processing
self.update_attributes(:processing => true)
dosomethingelse....
.where(:sent_time => nil).where(:processing => nil).gt(:retries => 0).asc(:send_time).all.entries
:processing => nil
Ruby uses truthy and falsey.
false and nil are falsey, everything else is truthy.
if true
puts "true is truthy, duh!"
else
puts "true is falsey, wtf!"
end
Output is "true is truthy, duh!"
if nil
puts "nil is truthy"
else
puts "nil is falsey"
end
Output is "nil is falsey"
if 0
puts "0 is truthy"
else
puts "0 is falsey"
end
Output is "0 is truthy"
See this explanation True and False
You could use double negating to "cast" an object to a boolean value:
!!nil # false
!!false # false
!!true # true
In general, only nil and false gives false as result. So, in if statements nil and false are interchangeable.
Yes, dosomethingelse gets run.
In ruby (almost nearly absolutely) everything is an object and every object is either "truthy" or "falsey". In general, everything is "truthy" except for the two constants, nil and false. This means that the code if foo != nil can be written more succinctly as if foo. You are branching based on the "nilness" of a particular value - similar to how you might more explicitly check for foo == null in more traditional languages.
A pattern where this shows up a lot is with ruby Hashes. By default a hash returns nil if a key is missing. So you might have code that works like this:
def foo(opts = {}) # Optional named arguments
# If :bar is not found, than => nil, so the first part of the conditional
# evalutates to false and we return the result of the second expression
bar = opts[:bar] || default_bar
end
There is an important caveat though! false and nil are not the same. Both semantically and in practice. Sometimes you actually want a boolean and then you need to be sure that you are checking explicitly for either that boolean or for nil (depending on what you are testing).
def display(opts = {})
# This will always result in fullscreen = true!
fullscreen = opts[:fullscreen] || true
end
Related
I frequently find myself writing Ruby code where I check for the presence of a value and subsequently do something with that value if it is present. E.g.
if some_object.some_attribute.present?
call_something(some_object.some_attribute)
end
I think it would be cool, if it could be written as
some_object.some_attribute.presence { |val| call_something(val) }
=> the return value of call_something
Anyone know if there's such a feature in Ruby or though activesupport?
I opened a pull request for this feature.
You can use a combination of presence and try:
If try is called without arguments it yields the receiver to a given block unless it is nil:
'foo'.presence.try(&:upcase)
#=> "FOO"
' '.presence.try(&:upcase)
#=> nil
nil.presence.try(&:upcase)
#=> nil
You could try
do_thing(object.attribute) if object.attribute
This is usually fine, unless the attribute is a boolean. In which case it will not call if the value is false.
If your attribute can be false, use .nil? instead.
do_thing(object.attribute) unless object.attribute.nil?
Though there is no such functionality out of the box, one could do:
some_object.some_attribute.tap do |attr|
attr.present? && call_smth(attr)
end
On the other hand, Rails provides so many monkeypatches, that one could append one to this circus:
class Object
def presense_with_rails
raise 'Block required' unless block_given?
yield self if self.present? # requires rails
end
def presense_without_rails
raise 'Block required' unless block_given?
skip = case self
when NilClass, FalseClass then true
when String, Array then empty?
else false
end
yield self unless skip
end
end
I have a database object in active record. If I call object.find(1).present? it returns false, but it exists. Calling !object.find(1).nil? returns true.
Why is this? I thought !nil == present?.
nil? and present? are not opposites.
Many things are both not present? and not nil?, such as an empty string or empty array.
"".present? # => false
"".nil? # => false
[].present? # => false
[].nil? # => false
To better answer your question lets look at the implementation:
def present?
!blank?
end
We don't see nil? mentioned here, just blank?, so lets check out blank? as well:
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
So essentially, if the object responds_to empty? it will call out to that for the result. Objects which have an empty? method include Array, Hash, String, and Set.
Further Reading
The Blank/Present Source in ActiceSupport
A concise explanation of nil v. empty v. blank in Ruby on Rails
So
shout = "gabba gabba hey"
of course does
shout.include?("gabba")
=> true
shout.include?("nothing")
=> false
Also this works
shout.include?("gabba"||"nothing")
=> true
However this doesn't
shout.include?("nothing"||"gabba")
=> false
I'm confused. Doesn't this operator work in an include at all, does it stop after evaluating the first value no matter if it returns true or false, or am I just missing something essential? Of course I could use this far longer code
shout.include?("nothing") or shout.include?("gabba")
=> true
but I'd rather have it short and concise.
You should use regexp instead:
!! (shout =~ /(gabba|nothing)/)
/(gabba|nothing)/ is a regular expression matching 'gabba' or 'nothing'
=~ returns the position of the regular expression in your string, if found
!! makes sure the result of the operation is true or false
Basically, you can't.
What you tried:
shout.include?('gabba' || 'nothing')
is equivalent to
shout.include?('gabba')
because
'gabba' || 'nothing'
# => 'gabba'
and this is how || operator works in Ruby. It returns first operand unless it's false or nil. Otherwise, it returns second operand. Since your first operand is 'gabba' string, it's being returned.
My "Project" Table have invoice as integer attribute, Here I put nil object to this attribute in DB. During evaluation nil.empty? occurs.
Code written at HAML extentions
- #project.each do |proj|
=proj.invoice if !proj.invoice.blank? || !proj.invoice.empty? || !proj.invoice.nil?
- #project_invoice=proj.invoice
=#project_invoice=0 if proj.invoice.blank? || proj.invoice.empty? || proj.invoice.nil
I receive this error while running code.
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
There's a few standard tests provided by Ruby and rails that can help, but you usually don't need to use all of them at once:
# Rails provided Object#blank? method
nil.blank? # => true
false.blank? # => true
''.blank? # => true
[ ].blank? # => true
# Ruby provided Object#nil? method
nil.nil? # => true
false.nil? # => false
''.nil? # => false
[ ].nil # => false
# Ruby class-specific #empty? method
nil.empty? # => error
false.empty? # => error
''.empty? # => true
[ ].empty? # => true
In your case the test you're probably looking for is actually a different one altogether. The opposite of blank? is present? and it comes in very handy for situations like this. You can even collapse down both of your inverted logical tests into a simple ternary query:
- #project_invoice = proj.present? ? proj.invoice : 0
More verbosely it looks like this:
- if (proj.present?)
#project_invoice = proj.invoice
- else
#project_invoice = 0
The present method verifies that the variable represents a non-nil, non-blank value of some sort.
The second condition has a misspelled variable name. It should be proj, not projt.
That would cause your issue.
if the invoice column is nill, then !proj.invoice.blank? evaluates to false, and the next test is done, !projt.invoice.empty?
since invoice is nil, you have nil.empty? which is an error, as empty? can not run on nil.
ruby-1.9.2-p0 > !nil.blank? || !nil.empty?
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
I think you are doing an overkill, since an integer should not be an array. I think you should just shorten it to only test blank?, as that catches an empty array too.
Is this is the code you are using. If this is the same code, I see a spelling mistake in the
second line.
Can you try with
=proj.invoice if !proj.invoice.blank? || !proj.invoice.empty? || !proj.invoice.nil?
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
Can you help me understand what's happening in the code above? I'm new to Rails/Ruby.
Thanks
It's negation (!) operator repeated twice.
Note that only ruby objects evaluating to false (in boolean expression) are nil and false itself.
Therefore,
some_role will be true, !some_role is false and !!some_role is true again.
nil is false, !nil is true and !!nil is false.
So, this is a "clever" way to check whether role returned from find_by_name is nil or not. (And therefore whether role with such name exists or not)
I guess, I don't have to tell you that doing this is bad for readability. You can always check if result is nil by normal means, like result.nil? or result == nil.
This is more readable. No need for the 'self' or 'return'. 'present?' is the opposite of 'nil?' so no negation is required.
def role?(role)
roles.find_by_name(role.to_s.camelize).present?
end