Why .where(:attribute => nil) checks for nil value? - ruby-on-rails

So here is the query, very simple:
field = :has_bill
value = nil
scoped.where(field => value)
And it outputs as:
(`electricity_profile_segment_summaries`.`has_swimming_pool` IN ('') OR `electricity_profile_segment_summaries`.`has_swimming_pool` IS NULL)
Which includes nil values and 0 values as well. Which is not correct, I would like to represent only NULL values from the table.
Any help appreciated

How about manually limiting to NULL for the nil case?
if value.nil?
scoped.where( "#{field} IS NULL" )
else
scoped.where( field => value
end

Related

Ruby - loop to check if at least one pair of values are populated

So in my rails form there are several rows of 2 textfields. For the form to save ok, at least one of the pair of textfields needs to be filled out.
So
nil nil
10 20
nil nil
nil nil
is valid.
This:
nil nil
nil nil
nil nil
nil nil
is invalid
This:
nil 10
nil nil
nil nil
nil nil
is invalid
Here is the method I am using to check all the fields (note that single_field and aggregate_field are strings and are the field names):
def no_values_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.each do |item|
return false if "!item.#{single_field}".nil? && "!item.#{aggregate_field}".nil?
end
true
end
But I guess this doesn't work as it will return true or false several times and will determine that a row is invalid even though a previous row may have been valid.
I need an overall true or false.
How can this be achieved?
Try leveraging any? or none? from the Enumerable module.
Your code could be rewritten as
def no_values_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.none? { |item|
!(item.send(single_field).nil?) && !(item.send(aggregate_field).nil?)
}
end
although I think that it would be clearer to have the condition be positive and to return true when there is a match found. I would write
def any_pairs_present?(single_field, aggregate_field)
self.lo_item.lo_line_items.any? { |item|
!(item.send(single_field).nil?) && !(item.send(aggregate_field).nil?)
}
end
Note that "!item.#{single_field}" will never be nil because it will always be a string! If you want to access instance fields dynamically then one way to do that is with send, but for other options you could look here which suggests the alternatives of instance_eval and instance_variable_get.
The function looks ok, but there seems to be syntax errors, I'd also make a few amendments:
def form_valid?(single_field, aggregate_field)
self.lo_item.lo_line_items.each do |item|
return true if !item.send(single_field).nil? && !item.send(aggregate_field)
end
false
end

How to return nil when adding two nil columns

I am trying to perform a sum calculation. If it has 2 nil values then it needs to return nil but it is returning 0. How do I fix this issue?
This is what I am doing:
rating_size1=company_ratings.collect(&:r1).count
update_attributes(:attrib1 => company_ratings.sum("r1").to_f/rating_size1)
If r1 is nil then the calculation should return nil. How can I do this?
Why not change it to
update_attributes(:attrib1 => (company_ratings.sum("r1").to_f/rating_size1 if company_ratings.any?))
or
update_attributes(:attrib1 => (company_ratings.sum("r1").to_f/rating_size1 if rating_size1 > 0))

`try` method when trying to fetch hash value

I'm trying to avoid an error message when pulling from a hash which may or may not have a value. I either want it to return the value or return nil.
I thought the try method would do it, but I'm still getting an error.
key not found: "en"
My hash is an hstore column called content... content['en'], etc.
content = {"es"=>"This is an amazing event!!!!!", "pl"=>"Gonna be crap!"}
Try method
#object.content.try(:fetch, 'en') # should return nil, but errors even with try method
I thought this would work but it doesn't. How else can I return a nil instead of an error?
Also, the content field itself might also be nil so calling content['en'] throws:
undefined method `content' for nil:NilClass
If you need to allow for object.content.nil?, then you'd use try. If you want to allow for a missing key then you don't want fetch (as Priti notes), you want the normal [] method. Combining the two yields:
object.content.try(:[], 'en')
Observe:
> h = { :a => :b }
=> {:a=>:b}
> h.try(:[], :a)
=> :b
> h.try(:[], :c)
=> nil
> h = nil
=> nil
> h.try(:[], :a)
=> nil
You could also use object.content.try(:fetch, 'en', nil) if :[] looks like it is mocking you.
See the Hash#fetch
Returns a value from the hash for the given key. If the key can’t be found, there are several options: With no other arguments, it will raise an KeyError exception; if default is given, then that will be returned; if the optional code block is specified, then that will be run and its result returned.
h = { "a" => 100, "b" => 200 }
h.fetch("z")
# ~> -:17:in `fetch': key not found: "z" (KeyError)
So use:
h = { "a" => 100, "b" => 200 }
h.fetch("z",nil)
# => nil
h.fetch("a",nil)
# => 100
Just use normal indexing:
content['en'] #=> nil
As of Ruby 2.0, using try on a possibly nil hash is not neat. You can use NilClass#to_h. And for returning nil when there is no key, that is exactly what [] is for, as opposed to what fetch is for.
#object.content.to_h["en"]

Can't use where on a column with nil value

I have an Article model
Article.last.publish
=> nil
Article.last.publish != true
=> true
Article.where("publish != ?", true)
=> []
Why am I getting an empty array there?
There are only 2 falsy values in ruby : false and nil
So, if you check the value of !nil then the output will be true
So with your first statement
Article.last.publish # its output is nil
Then your second statement
Article.last.publish != true # this is correct , since !nil = true
But the last one
Article.where("publish != ?", true)
gets converted into a query as
SELECT `articles`.* FROM `articles` WHERE (publish != 1)
which means all articles whose publish value is not true, which means false
and false is not equal to nil.
nil and false are two different falsy values.
Try Article.where(publish: false)

How do you return a boolean value for a regexp scan of an integer?

I'm looking through my object attributes for culprits that are not :
^[1-3]{3}$
What is the method used to scan integers for regexp?
Some examples:
124.to_s.match(/^[1-3]{3}$/)
=> nil
123.to_s.match(/^[1-3]{3}$/)
=>#<MatchData "123">
Since nil is considered as false, you have your boolean.
Ex:
"no yo" if 124.to_s.match(/^[1-3]{3}$/)
=> nil
"yo!" if 123.to_s.match(/^[1-3]{3}$/)
=> "yo!"
You may use also one of the following:
def is_pure_integer?(i)
i.to_i.to_s == i.to_s
end
or
'132' =~ /^\d+$/ ? true : false

Resources