How to make boolean as method result? - ruby-on-rails

I create a method which is supposed to send me a boolean.
But within it there is a loop who send also boolean.
Sometimes the loop send true sometimes false and I would like my method to send true as soon there is one true.
def update_with_former_email?(update_email)
self.versions.each do |version|
next if version.object.nil?
version.object.include?(update_email)
end
end
For the moment when I call my method like:
person.update_with_former_email?("orsay#gmail.com")
it sends me the whole object self.versions

each returns the object it was called upon, i.e. self. To return an actual boolean value derived from include?, you can use return:
def update_with_former_email?(update_email)
self.versions.each do |version|
next if version.object.nil?
return true if version.object.include?(update_email)
end
return false
end
or better use any? instead of each:
def update_with_former_email?(update_email)
self.versions.any? do |version|
version.object.present? && version.object.include?(update_email)
end
end

Related

how to pass parameters enum in method any?

How to parameterize enum? I want to use my enum value in method any? to check true or false for my ActiveRecord
I have method is_any? to check my ActiveRecord
def is_any? status
album.voice_guides.all_except(params[:ids]).any?(&status?)
end
And call is_any? in this method
def verify_bulk_destroy
return if album.pending?
if album.publish?
raise Api::Error::ControllerRuntimeError, :error unless is_any?
(:publish)
end
end
But it raise error
undefined method `status?' for #<Api::Admin::Albums::PremiumGuidesController:0x0000000000d278>
Did you mean? status
status=
Just change your is_any? method to
def is_any?(status)
album.voice_guides.all_except(params[:ids]).any? { |guide| guide.status == status }
end
which will load all records into memory first as your method did before.
Or to this when you want to check the condition in the database without loading the records into memory which might be faster depending on your needs:
def is_any?(status)
album.voice_guides.all_except(params[:ids]).where(status: status).exists?
end

rubocop app controller function validate param integer use of nil? predicate

I tried rewriting this function numerous ways to get around this error, however, I want to defer to other experts before I disable the cop around it.
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
This is used like so:
def index
if params[:job_id] && numeric?(params[:job_id])
This issue was solved via: Checking if a variable is an integer
Update trying:
def numeric?(string)
!!Kernel.Float(string)
rescue TypeError, ArgumentError
false
end
Reference How do I determine if a string is numeric?
New error:
def numeric?(arg)
!/\A[+-]?\d+\z/.match(arg.to_s).nil?
end
Passes all Rubocop tests from a default configuration. Complete gist with tests at https://gist.github.com/aarontc/d549ee4a82d21d263c9b
The following code snippet does the trick:
def numeric?(arg)
return false if arg.is_a?(Float)
return !Integer(arg).nil? rescue false
end
Returns false for the following: 'a', 12.34, and '12.34'.
Returns true for the following: '1', 1.
You can write the method
def numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/).nil?
end
You really don't need to do nil comparisons and then based on the decision returning true/false. #nil? method does it for you.

Rails application helper return if false

I'm writing a helper method to determine if current has any pending reviews to write. If there is a pending review, simply print a line in the view.
My helper is putting exactly the right stuff to the console, however I'm struggling with how to simply return it. In this scenario, current user has an id: 4.
My Code:
def review_pending
gallery = current_user.galleries.first
if gallery
if gallery.permissions.accepted
gallery.permissions.accepted.each do |p|
return true if p.user.reviews.find_by_reviewer_id(!current_user)
puts "already written review: #{p.user.reviews.find_by_reviewer_id(4)} - prints correctly"
end
end
end
end
My goal: if there is a user from the list that current user has not yet reviewed return true.
Thanks!!!
Thanks for all your pointers!
I had forgotten/learned 2 things to make it work:
First, if nil is returned, ruby returns the last returned value which in my case was true (if gallery.permissions.accepted).
Secondly, I placed the "!" before current_user, and should have placed it before the entire line.
Corrected Code:
def review_pending
gallery = current_user.galleries.first
if gallery
gallery.permissions.accepted.each do |p|
return !p.user.reviews.find_by_reviewer_id(current_user.id)
end
end
return false
end

How can you detect when "break" is called in the callers Proc?

I'm writing a library that iterates over a set and calls the caller's proc for every item in the set. Example:
def self.each(&block)
# ... load some data into results_array
results_array.each do |result|
status = block.call(result)
# how do I know to call break if the user calls break?
break if status == false
end
end
Currently, as you can see in my code, I inspect the "last expression evaluated" in order to break. This seems bug-prone as the end-user may have a perfectly valid reason for their last expression evaluating to false. The more appropriate thing would be to detect the caller using "break".
How do I know to call break if the user calls break?
If you use yield instead of block.call, you can use the difference in behavior between next and break. As an example:
def each(&block)
puts "before"
result = yield
puts "after"
result
end
each do
puts "hello"
next
end
# Result:
# before
# hello
# after
each do
puts "hello"
break
end
# Result:
# before
# hello
As you can see, when you use next inside a block, the control is given back to the function calling the block. If you use break however, the calling function will return immediately with nil as a return value. You could now exploit this behavior with some trick:
def each(&block)
# ...
results_array.each do |result|
block_result = yielder(result, &block) || {:status => :break, :value => nil}
if block_result[:status] == :break
# block has called break
#...
else
# block has called either next or the block has finished normally
#...
end
end
end
def yielder(*args, &block)
value = yield *args
{:status => :normal, :value => value}
end
This works because here, the yielder function returns either nil in case the block called break or a hash with a status and the return value of the block. You can thus differentiate between a valid result (which is always different from nil) and an exceptional result which is always nil.
This should work, unless I don't understand what you are trying to do:
def each(&block)
# ... load some data into results_array
results_array= [1, 2, 3]
results_array.each do |result|
block.call(result)
end
end
each do |result|
puts result
break
end

Building a Rails scope using `tap`

I have a method that looks something like
class Student < ActiveRecord::Base
def self.search(options = {})
all.tap do |s|
s.where(first_name: options[:query]) if options[:query]
s.where(graduated: options[:graduated]) if options[:graduated]
# etc there are many more things that can be filtered on...
end
end
end
When calling this method though, I am getting back all of the results and not a filtered set as I would expect. It seems like my tap functionality is not working as I expect. What is the correct way to do this (without assigning all to a variable. I would like to use blocks here if possible).
tap will not work for this.
all is an ActiveRecord::Relation, a query waiting to happen.
all.where(...) returns a new ActiveRecord::Relation the new query.
However checking the documentation for tap, you see that it returns the object that it was called on (in this case all) as opposed to the return value of the block.
i.e. it is defined like this:
def tap
yield self # return from block **discarded**
self
end
When what you wanted was just:
def apply
yield self # return from block **returned**
end
Or something similar to that.
This is why you keep getting all the objects returned, as opposed to the objects resulting from the query. My suggestion is that you build up the hash you send to where as opposed to chaining where calls. Like so:
query = {}
query[:first_name] = options[:query] if options[:query]
query[:graduated] = options[:graduated] if options[:graduated]
# ... etc.
all.where(query)
Or a possibly nicer implementation:
all.where({
first_name: options[:query],
graduated: options[:graduated],
}.delete_if { |_, v| v.empty? })
(If intermediate variables are not to your taste.)
You can easily create a let function:
class Object
def let
return yield self
end
end
And use it like this:
all.let do |s|
s=s.where(first_name: options[:query]) if options[:query]
s=s.where(graduated: options[:graduated]) if options[:graduated]
# etc there are many more things that can be filtered on...
s
end
The difference between tap and let is that tap returns the object and let returns the blocks return value.
These days (ruby >= 2.5) you can use Object.yield_self:
def self.search(options = {})
all.yield_self do |s|
s = s.where(first_name: options[:query]) if options[:query]
s = s.where(graduated: options[:graduated]) if options[:graduated]
s
end
end

Resources