Possible bad code or Rails multi-thread issue - ruby-on-rails

I'm having an issue with the below code frequently in a Rails 4.4, Ruby 2.2 with puma web server application. This code has excessive if statements just to try and figure out the problem.
We can assume that assign_coupon() returns true or false. When it returns true it creates an association between the review and the coupon, so you can type review.coupon. Before you run assign_coupon() or if assign_coupon() returns false review.coupon will be nil.
The issue is that assign_coupon() is not working and review.coupon is nil, yet the code gets past 'if CouponCodeService.assign_coupon(review)' and then also passes 'if !review.coupon.nil?' and is running 'review.approve!'.
I cannot figure out for the life of me how the code gets passed 2 failing if statements to run 'review.approve!'. This should not be possible.
if review.product.has_coupon_codes?
if CouponCodeService.assign_coupon(review) # this is false
if !review.coupon.nil? # this is false
review.approve! # this is some how executed.
success_message(review)
review.send_reviewer_approved_email
else
review.update(aasm_state: 'requested')
error_message(review)
end
else
review.update(aasm_state: 'requested')
error_message(review)
end
end
def self.assign_coupon(review)
begin
product = review.product
if product.has_coupon_codes?
coupon = product.coupons.where(claimed: false).first
coupon.review_id = review.id
coupon.claimed = true
if coupon.save
return true
else
return false
end
else
return false
end
rescue Exception => e
return false
end
end

Related

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.

cancan rails code understanding

I am unable to debug some of cancancan code and looking for some help.
can :update, Message do |m|
false
end
But strangely cancancan always return true and i am unable to debug the issue.Here is a small piece of relevant cancancan code
rule.rb
def matches_conditions?(action, subject, extra_args)
if
...
elsif #block && !subject_class?(subject)
#block.call(subject, *extra_args)
end
end
I can see that the #block.call is made and it return false but this piece of code in the ability.rb does not make sense to me
match = subject.map do |subject|
relevant_rules_for_match(action, subject).detect do |rule|
rule.matches_conditions?(action, subject, extra_args)
end
end.compact.first
match ? match.base_behavior : false
The base_behaviour is never set after initialization, and set to true at initialization, how would base_behaviour of a rule would ever return false.
The helper function is called
ability = Ability.new(user)
ability.can? :update ,#message
Got it there was a overriding ability

Nested transactions and rollbacks in rails

My question is in regards to using nested transactions in rails with ActiveRecord.
What I need to do is make sure both saves are successful else rollback if ether fail and return true or false based on the success.
Hers is the code
Card.transaction do
Transaction.transaction do
#card_saved = card.save
#transaction_saved = self.save
end
raise ActiveRecord::Rollback
end
if #transaction_saved and #card_saved
return true
end
return false
Do I need to add a rollback in the inner block as well or will the outer catch both?

false vs 0 while serving object in database Rails

There is the following code:
class BeautySalonCategory < ActiveRecord::Base
before_create :set_default_values
protected
def set_default_values
self.available = false
end
end
When I use Rails console and input 'BeautySalonCategory.create!(name: "Some name")' I get the following error:
ActiveRecord::RecordNotSaved
But if I change 'self.available = false' to 'self.available = 0' then no errors won't appear. Why? Thanks.
There's two things going on: Rails expects your before_create handlers to return a non-false value when they successfully run, and the result of an a = b statement in Ruby is b. So your self.available = false version returns false, indicating to Rails that the before_create failed. If you define your method like this, everything will be fine:
def set_default_values
self.available = false
true
end
(Props to maringan for spotting this in the comments.)

What does a bang before a variable do?

I am reading through the RoR guide on testing (http://guides.rubyonrails.org/testing.html)
About 1/5th down the page it says ""To see how a test failure is reported, you can add a failing test to the post_test.rb test case."
test "should not save post without title" do
post = Post.new
assert !post.save
end
I am trying to understand what the use of the bang (!) before post save means.
In an app that I am developing I have a validattion in the model for post
validates :post, presence: true
If I leave the line as it is, the test passes.
If I remove the bang the test fails (because of the validation)
If I move the bang to after the save an exception is raised (because the validation fails
and the bang returns the error message, I think)
So can you help me understand please, what does the bang in front do nd why does it make the test pass?
Question edit / extension: Why is the second test a fail (F) and not an exception (E)
The bang (!) inverts the result of post.save
assert post.save reads assert that the post does save
assert !post.save reads assert that the post doesn't save
Check out the Ruby Logical Operators section at http://www.tutorialspoint.com/ruby/ruby_operators.htm
Edit for extended question:
assert looks for a true result. If the result is true, it returns a pass for that test. If the result is not true, it returns a fail for that test.
Some pseudo code for the asset method,
def assert(result)
if result == true
return 'Pass'
else
return 'Fail'
end
end
assert true
=> 'Pass'
assert false
=> 'Fail'
If there is an exception in the test or code, the test method will rescue the exception and return (E).
Some pseudo code for the test method,
def test(description, &block)
begin
yield
rescue
return 'Exception'
end
end
test 'test description' do
raise 'An error occurred'
end
=> 'Exception'
! is the Logical Not prefix operator - it is not related to variables or methods.
It can be summarized as:
x !x
--------- ---------
nil true
false true
true false
<other> false
(In this case x is the result of evaluating post.save.)

Resources