Using Ruby's ternary operator ? : to shorten this - ruby-on-rails

I wonder if there’s a way to tighten this up:
def find_by_recordtype
e = EvLk.find_by_sql(<SQL QUERY>)
return (e.size > 0 ? e : nil)
end
I could do something like below but, prefer not to query twice.
return ( EvLk.find_by_sql().size > 0 ? EvLk.find_by_sql() : nil)

You're using find_by_sql so presumably you're in Rails or have ActiveSupport available. In that case, you can use presence:
presence()
Returns the receiver if it's present otherwise returns nil. object.presence is equivalent to
object.present? ? object : nil
So you could do this:
def find_by_recordtype
EvLk.find_by_sql(<SQL QUERY>).presence
end

One thing you can do is memoize the result.
Whether this makes sense depends on the context of the object and the app.
def find_by_recordtype
return #records if #records
#records = EvLk.find_by_sql(<SQL QUERY>)
end
+1 for ruby nuby.
BTW, why do you want to return nil? Usually it's better to the same type for all cases.

EvLk.find_by_sql(<SQL QUERY>).tap{|e| break if e.empty?}

Related

Better way to check 2 conditions based on 1 object

I commonly need to use this kind of methods where I have to check if an object exists and if this object returns a specific value or a behavior. Is that a better way to write this code?
def set_current_theme
if current_tenant && current_tenant.has_custom_domain?
#theme = Theme.last || Theme.create
end
end
At a first glance, I would just add one conditional: if current_tenant.has_custom_domain? and that should be enough. But the result is generally that there is no such method (in this case has_custom_domain?) for nil class.
Shorter (and i think better) way is to use &. (it's shorthand for try!) like this.
if current_tenant&.has_custom_domain?
#theme = Theme.last || Theme.create
end
What does &. (ampersand dot) mean in Ruby?
I would suggest early return (so called guard clause) instead of :if statement, because you don't have :else clause:
def set_current_theme
return unless current_tenant&.has_custom_domain?
#theme = Theme.last || Theme.create
end

How to check a key/method on a object which can be hash as well as another class

Lets say we have two classes:
class Test
end
class Test2
def a
end
end
and say we have a variable var which can point to an object of these class or a Hash, so:
var = Test.new
or
var = Test1.new
or
var = {"a" => 1}
Now we need to ensure that we call 'a' on 'var' only if its allowed (i.e. it should not be called in case it points to Test).
So, if I do:
var.a
it gives an error in case var points to Test object. Is there any way we can prevent the error? (Any other solution apart from doing .is_a? test ?)
You could use respond_to? to check if you can call the method on the object:
var.a if var.respond_to? :a
Strange questions lead to nasty answers. But at least it's working:
def a(test)
(test.respond_to?(:a) ? test.a : nil) ||
(test.respond_to?('has_key?') && test.has_key?('a') ? test['a'] : nil)
end
You can rescue from error, and return a default value, something like this
result = var.a rescue ""
Here blank string is used as default for illustration purposes, you can pick a reasonable default for your case

How to call local variable value in a method through a parameter?

In my Rails app I have this (rather silly) method:
def my_method(param)
foo = "hey"
bar = "ho"
if param == :foo
return foo
elsif param == :bar
return bar
end
end
I don't like the if/else block, though.
Is there a simpler way to return the value of the local variable foo if :foo is provided as a parameter?
Or will I have to use an array or a hash here?
If you're using the very latest Ruby, you can use binding.local_variable_get(param). A hash seems cleaner to me, but your mileage may vary.
This should look simpler, don't think introducing a new data structure is required:
def my_method(param)
return 'hey' if param == :foo
return 'ho' if param == :bar
end
You can use a Hash:
def my_method(param)
objs = {
foo: "hey",
bar: "ho"
}
objs[param]
end
This is really a good time to use a case statement:
def my_method(param)
case param
when :foo
'hey'
when :bar
'ho'
else
# what do you want to do here?
end
end
Something to consider is, you're using an if/elseif, but what happens if neither of those hit? Do you want to return nil, or trap an error? As you look around in other people's code, you'll sometimes find long chains of if/elseif tests, with no final else, which opens up a potential logic error and can result in a hard-to-find bug.

Rails/Ruby one-liner unless zero/nil?

Is there a way to make this situation more compact in rails views?
Eg I have haml
= object.count unless object.count ==0
I sort of don't like that has I'm repeating the function there, I would much rather have something like
= object.count unless ==0
Eg if I had more complex statements
= object.relations.where(attribute: "something").count unless zero?
I could split that into two lines say
- cnt = object.relations.where(attribute: "something").count
= cnt unless cnt==0
But for each situation I would have multiple lines, and storing a variable to use once sucks.
EDIT: just to elaborate I want to check if the number is 0, and if so not display anything. It looks nicer in the view that way.
UPDATE:
One of the answers made come up with a solution along these lines
class Object
def unless
self unless yield(self)
end
end
So I can call whatever object I have with a block eg. .unless{|c| c<1}
This lets me tack the conditionals on, and keeps it pretty clear what is going on :), bonus is as it's block driven I can use this on any object :P.
Thanks everyone :)
UPDATE EVEN MORE
Having |c| in the block sucked. So I looked up the api and changed it too
class Object
def unless(&block)
self unless instance_eval(&block)
end
end
So now I can use .count.unless{zero?} to accomplish this :P. Or if I have a complicated condition I can add that in with |c| etc.
If object is an array you can use object.empty? (or object.any? for the reverse case)
Just create a view helper:
def display_count_or_nothing(array)
array.count unless array.count == 0
end
In the view you can use it like this:
<%= display_count_or_nothing(array) %>
i think the following is nice and clear, although i hate the variable "object",
it would be much nicer if the name of the variable described the contents of the array (as plural)
= object.count unless object.empty?
If this is only about count, you can monkey patch Enumerable:
module Enumerable
def count_or_empty_string
self.any? ? self.count : ''
end
end
If object is an enumerable, you can do this:
= object.count_or_empty_string
This will return an "" if object.count == 0 else it will return an integer. So there is no need for unless or if in your HAML anymore.

Rails ternary operator and 'this'

Does Rails have a this like javascript/Jquery does?
Take this example:
User.find_by_email(params[:candidate][:email].present? ? (u = this.id) : (u = 'not here')
or:
if User.find_by_email(params[:candidate][:email].present?
a += 1
user = this
end
I'm aware that this code might be rewritten in more efficient ways in this case, but my question is about being able to use this. Does Ruby have something like this?
In the context of a class you use self.
In these cases though this code is not in User context so you have to make an assignment.
u = User.find_by_email(params[:candidate][:email])
user_name = u.any? ? u.name : 'not here'
I prefer .any? to .present? in this context as it reads better.
Ruby uses self to denote this. I am not quite sure if you need to use self for your problems.
First scenario can be rewritten as:
u = User.find_by_email(params[:candidate][:email]).try(:id) || 'not here'
Second scenario can be rewritten as:
user = User.find_by_email(params[:candidate][:email])
a += 1 if user.present?
I'm guessing the more idiomatic ruby approach for your case would be something like the following:
User.where("email in (?)", email_arr).each do |user|
a += 1
user.foo = bar
end
but it's hard to say without seeing the all code.

Resources