Skip `if` in case that statement is not possible - ruby-on-rails

In my rails contoller I have this code:
if Photo.find(params[:photo_id]).patient_id == nil
.........
else
.........
So at the time I get a error when there are no params[:photo_id]:
Couldn't find Photo without an ID
I know that I could fix it with: For example:
if(params[:photo_id]) && (Photo.find(params[:photo_id]).patient_id == nil)
But now I tried to write an exception "how its called I think":
if Photo.find(params[:photo_id]).patient_id == nil rescue false
That throws a new error:
syntax error, unexpected modifier_rescue, expecting keyword_then or ';' or '\n' if
So what did a wrong?(I'm beginner in programming!)

You just need some parens.
if (Photo.find(params[:photo_id]).patient_id == nil rescue false)
...
end

The syntax is wrong. Try:
begin
if Photo.find(params[:photo_id]).patient_id == nil
.........
else
.........
rescue
false
end

Photo.find_by_id(params[:photo_id]).try(:patient_id)
Avoid using exceptions for situations that are not exceptional... and by the sounds of it, you're expecting to occasionally to have a Photo that doesn't get found.

Related

ruby - refactoring if else statement

I've tried reading some tutorials on refactoring and I am struggling with conditionals. I don't want to use a ternary operator but maybe this should be extracted in a method? Or is there a smart way to use map?
detail.stated = if value[:stated].blank?
nil
elsif value[:stated] == "Incomplete"
nil
elsif value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save(value[:stated])
end
If you move this logic into a method, it can be made a lot cleaner thanks to early return (and keyword arguments):
def stated?(stated:, is_ratio: nil, **)
return if stated.blank? || stated == "Incomplete"
return stated == "true" if is_ratio == "true"
apply_currency_increment_for_save(stated)
end
Then...
detail.stated = stated?(value)
stated = value[:stated]
detail.stated = case
when stated.blank? || stated == "Incomplete"
nil
when value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save stated
end
What's happening: when case is used without an expression, it becomes the civilized equivalent of an if ... elsif ... else ... fi.
You can use its result, too, just like with if...end.
Move the code into apply_currency_increment_for_save
and do:
def apply_currency_increment_for_save(value)
return if value.nil? || value == "Incomplete"
return "true" if value == "true"
# rest of the code. Or move into another function if its too complex
end
The logic is encapsulated and it takes 2 lines only
I like #Jordan's suggestion. However, it seems the call is incomplete -- the 'is_ratio' parameter is also selected from value but not supplied.
Just for the sake of argument I'll suggest that you could go one step further and provide a class that is very narrowly focused on evaluating a "stated" value. This might seem extreme but it fits with the notion of single responsibility (the responsibility is evaluating "value" for stated -- while the 'detail' object might be focused on something else and merely makes use of the evaluation).
It'd look something like this:
class StatedEvaluator
attr_reader :value, :is_ratio
def initialize(value = {})
#value = ActiveSupport::StringInquirer.new(value.fetch(:stated, ''))
#is_ratio = ActiveSupport::StringInquirer.new(value.fetch(:is_ratio, ''))
end
def stated
return nil if value.blank? || value.Incomplete?
return value.true? if is_ratio.true?
apply_currency_increment_for_save(value)
end
end
detail.stated = StatedEvaluator.new(value).stated
Note that this makes use of Rails' StringInquirer class.

Implicit return value and compile errors in ruby

Consider the following code in a class in ruby:
def isDarkSide
true
end
The return value of isDarkSide is true
However, when I run ruby -c on the following code:
def can_join_group? any
DeathStar::Tie::BOT, self, nil
end
I endup with the following errors:
dynamic constant assignment
DeathStar::Tie::BOT, self, nil
^
Can't change the value of self
DeathStar::Tie::BOT, self, nil
^
Can't assign to nil
syntax error, unexpected '\n', expecting '='
However, the problem can be fixed by writing
def can_join_group? any
return DeathStar::Tie::BOT, self, nil
end
Can someone explain to me why do I need to use the return keyword ? I feel like I'm missing something important in ruby language.
To return multiple values, you should use either explicit return or array of values.
Also 1, 2, 3 is not even a valid Ruby syntax.
def multi_return1
return 1, 2, 3
end
def multi_return2
[1, 2, 3]
end
multi_return1 == multi_return2
#=> true

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

Ruby operator overloading method from block

I'm using Ruby 1.9.2. For example i've got class :
class Test
def ==(param)
# some process
end
def bar(param)
puts "foo bar #{param}"
end
end
I can invoke bar method using :
Test.new.instance_eval{ bar 'celona' }
But i cannot execute == method from block like
Test.new.instance_eval{ == "foo" }
i've got syntax error, unexpected tEQ
The following worked for me:
class Test
def ==(param)
p "You put #{param}"
end
end
Test.new.instance_eval{|a| a == "foo" }
=> "You put foo"
The solution really depends on your use case.
Edit The same holds true for when you instantiate a class.
b = Test.new
b == "foo"
=> "You put foo"
You can also use self
Test.new.instance_eval{self == "foo" }
I am not entirely sure of the reason, but I would guess that the == method required an explicit callee and it can't infer self
You can try :
Test.new.send("==", "foo")

strange nil object result

I have a module:
module Voteable
def has_up_vote_of user
return ! self.votes.select{|v| v.user.id == user.id && v.value == 1}.empty?
end
def has_down_vote_of user
return ! self.votes.select{|v| v.user.id == user.id && v.value == -1}.empty?
end
end
Which is mixed into a model:
class Comment < ActiveRecord::Base
include Voteable
end
In a controller code, there is a check:
has_up_vote = #voteable.has_up_vote_of #user
has_down_vote = #voteable.has_down_vote_of #user
#voteable and #user are existing model items, found in a DB.
Suppose, voteable item has up-vote of user. After executing the code, has_up_vote will be equal to true, and has_down_vote will be nil.
Why nil, instead of false ?
I have used several variations of methods, but the problem is the same. Even this gives me the same effect:
def has_up_vote_of user
has = self.votes.select{|v| v.user.id == user.id && v.value == 1}.empty?
return !has.nil? && has
end
Posssible, i'm misunderstanding something, but this behavior is strange
Update
I've noticed very strange behaviour.
When i change methods to trivial:
def has_up_vote_of user
return false
end
def has_down_vote_of user
return false
end
They both returns nil, when i debug the app.
But, from console, they returns false.
It's more stange, because i cannot do anything with these results. These code is not working:
has_up_vote = false if has_up_vote.nil?
has_down_vote = false if has_down_vote.nil?
I think that the debugging environment you're running in is interfering with the actual value of has_down_votes. The select method should never return nil as defined.
Instead of !{}.empty? you could use {}.present?
Its more readable and the output will always be true/false only
I know this doesn't get to the root cause of your strange problem, but it should give you the results you want. Instead of
return ! self.votes.select{|v| v.user.id == user.id && v.value == -1}.empty?
try
return !!self.votes.select{|v| v.user.id == user.id && v.value == -1}.any?
The double exclamation point is intentional -- it will cause nil to become false. (!arr.empty? is equivalent to arr.any? which is equivalent to !!arr.any? -- except the last one converts the nil to false)

Resources