RSPEC - Test says object is nil, but works fine in practice - ruby-on-rails

I can't figure out why this object keeps coming up as nil.
Here is the error:
1) Item Calculate with just Total
Failure/Error: subject.calculate_tax(tax, sub_category)
TypeError:
nil can't be coerced into Fixnum
# ./app/models/item.rb:111:in `+'
# ./app/models/item.rb:111:in `calculate_tax'
# ./spec/models/item_spec.rb:26:in `block (2 levels) in <top (required)>'
Here is the line it applies to - it thinks "self.tax_rate" is nill (second last argument)
self.tax_amount = ((self.total - self.deduction) - ((self.total - self.deduction) / (1 + self.tax_rate))) * self.tax_adjustment
Here is my Test
describe Item do
subject {Item.new(:report_id => 26 , :name => 'Gas' ,:tax_rate => 0.13, :tax_id => 1 , :category_id => 15 , :sub_category_id => 31 , :job_id => 1 , :total => 20 )}
let(:tax) {Tax.where(id: subject.tax_id).first}
let(:sub_category) {SubCategory.where(id: subject.sub_category_id).first}
it 'Calculate with just Total' do
subject.name.should be == 'Gas'
tax = Tax.find_by_id(subject.tax_id)
subject.sub_category_id.should be == 31
subject.set_nil_values
sub_category.should_receive(:taxable).exactly(3).times.and_return(sub_category.taxable)
tax.should_receive(:rate).exactly(4).times.and_return(tax.rate)
sub_category.should_receive(:tax_adjustment).and_return(sub_category.tax_adjustment)
subject.calculate_tax(tax, sub_category)
subject.should_receive(:tax_rate).exactly(2).times.and_return(tax.rate)
subject.calculate_cost
subject.cost.should be_within(0.01).of(17.70)
subject.tax_amount.should be_within(0.01).of(2.30)
subject.save
end

Your taxes table in your test database appears not to have an entry with id equal to 1 whose tax.rate is not nil

Related

How to convert human readable number to actual number in Ruby?

Is there a simple Rails/Ruby helper function to help you convert human readable numbers to actual numbers?
Such as:
1K => 1000
2M => 2,000,000
2.2K => 2200
1,500 => 1500
50 => 50
5.5M => 5500000
test = {
'1K' => 1000,
'2M' => 2000000,
'2.2K' => 2200,
'1,500' => 1500,
'50' => 50,
'5.5M' => 5500000
}
class String
def human_readable_to_i
multiplier = {'K' => 1_000, 'M' => 1_000_000}[self.upcase[/[KM](?=\z)/]] || 1
value = self.gsub(/[^\d.]/, '')
case value.count('.')
when 0 then value.to_i
when 1 then value.to_f
else 0
end * multiplier
end
end
test.each { |k, v| raise "Test failed" unless k.human_readable_to_i == v }
Try something like this if you have an array of human readable numbers than
array.map do |elem|
elem = elem.gsub('$','')
if elem.include? 'B'
elem.to_f * 1000000000
elsif elem.include? 'M'
elem.to_f * 1000000
elsif elem.include? 'K'
elem.to_f * 1000
else
elem.to_f
end
end
Have a look here as well, you will find many Numbers Helpers
NumberHelper Rails.
Ruby Array human readable to actual

Converting hash ruby objects to positive currency

I have a hash where the keys are the months and I want to convert the objects to positive numbers AND currency.
INPUT
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
OUTPUT
hash = {
12 => 5888.96,
4 => 6346.10,
3 => 6081.76,
2 => 5774.79,
1 => 4454.38
}
#Output should be a float
Any help would be greatly appreciated.
Try
hash.transform_values{|v| v.round(2).abs()}
or
hash.update(hash){|k,v| v.round(2).abs()}
Numeric.abs() can be applied to ensure a number is positive and Float.round(2) will round a float to 2 decimal places. See ruby-doc.org/core-2.1.4/Numeric.html#method-i-abs and ruby-doc.org/core-2.2.2/Float.html#method-i-round for usage examples. Note that round() will not add trailing zeros since that does not affect numerical value, however trailing zeros can be added by formatting, for example:
hash = {
12 => -5888.969999999999,
4 => -6346.1,
3 => -6081.76,
2 => -5774.799999999999,
1 => -4454.38
}
# transform hash values
hash.each do |key, value|
hash[key] = value.abs().round(2)
end
# print the modified hash without formatting the values
hash.each do |key, value|
puts "#{key} => #{value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.1
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38
# print hash with values formatted with precision of 2 digits
hash.each do |key, value|
puts "#{key} => #{'%.2f' % value}"
end
# prints
# 12 => 5888.97
# 4 => 6346.10
# 3 => 6081.76
# 2 => 5774.80
# 1 => 4454.38

"bad value for range" is raised in rspec/turnip

I'm using turnip for testing.
I wrote the following test:
session = ActionDispatch::Integration::Session.new(Rails.application)
str = "Basic " + Base64.strict_encode64("#{#token}:#{#secret}")
session.get "/api/v1/recommend/#{n}", nil, {"Authorization" => str}
I used ActionDispatch::Integration::Session.new(Rails.application) because turnip don't support get.
#token and #secret are values for token and token_secret, and I confirmed these values are valid.
n is given at arguments.
Next, I run it and these errors occurred:
Failures:
1) test
Failure/Error: test1
ArgumentError:
bad value for range
# ./spec/features/recommendation.feature:13:in `test1'
# ./app/models/user.rb:682:in `recommendation'
# ./app/controllers/api/v1/users_controller.rb:209:in `recommendation'
# spec/steps/recommendation_steps.rb:32:in `block (2 levels) in <top (required)>'
# ./spec/features/recommendation.feature:14:in `block (6 levels) in run'
# ./spec/features/recommendation.feature:13:in `each'
# ./spec/features/recommendation.feature:13:in `block (5 levels) in run'
# -e:1:in `<main>'
I tried the following cases and confirmed they are successful.
Do same things in rails console
Make a dummy encoded string and use it (of course authentication was failing, but no error)
Why did such errors occur?
(Added)
./app/models/user.rb:682:in recommendation:
def recommendation limit = 10
result = Hash.new{0.0}
unused_recipe_ids = Recipe.where.not(id: self.made_recipes.pluck(:id)).pluck(:id)
self.made_activities.includes(:recipe).each do |activity|
c = coefficient(activity)
similarities = RecipeSimilarity.where(from_recipe_id: activity.recipe.id).where(to_recipe_id: unused_recipe_ids)
similarities.each { |s| result[s.to_recipe_id] += s.score * c }
end
Recipe.where(id: result.sort{|a, b| b[1] <=> a[1]}[0...limit].map{|r| r[0]})
end
def coefficient activity
return 1.5 if activity.type_code == 301
return 0.5 if activity.type_code == 302
if activity.type_code == 100
return 1.0 if activity.evaluation == 0
return 0.1 if activity.evaluation == 1
return 0.6 if activity.evaluation == 2
return 1.1 if activity.evaluation == 3
return 1.6 if activity.evaluation == 4
return 2.5 if activity.evaluation == 5
end
return 1.0
end
./app/controllers/api/v1/users_controller.rb:209:in recommendation:
def recommendation
#recipes = #current_user.recommendation(params[:limit])
render text: #recipes.to_json
end
Recipe.count is 50.
RecipeSimilarity.count is 2500.

`new': invalid date ( ArgumentError)

Ok i somehow get this error for an function with an date:
C:/geburtstag/app/config/initializers/update_year.rb:11:in `new': invalid date (
ArgumentError)
from C:/geburtstag/app/config/initializers/update_year.rb:11:in `block i
n <top (required)>'
The code looks like this:
Patient.all.each do |f|
if (f.birthday.get_birthday + 1) != f.year
f.update_attribute :year, f.birthday.get_birthday + 1
end
if f.thisyear.blank?
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month, f.birthday.mday )
end
if f.thisyear.year != Date.today.year
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month,f.birthday.mday)
end
end
Line 11:
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month, f.birthday.mday )
I dont get why i get this error!! SO i made some test in the console, that all worked fine! I hope you can help me! Thanks
irb(main):005:0> c = Patient.find(24367)
←[1m←[36mPatient Load (0.0ms)←[0m ←[1mSELECT "patients".* FROM "patients" WHE
RE "patients"."id" = ? LIMIT 1←[0m [["id", 24367]]
=> #<Patient id: 24367, vorname: "Hanz", nachname: "Schnitzel", birthday: "1961-06
-29", geschlecht: "1", drucken: nil, extraanrede: nil, extratext: nil, year: nil
, rund: nil, thisyear: nil, zuletzt: nil, strasse: "Lsu 15", ort: "W÷rth", pl
z: "93386", created_at: "2013-09-19 16:37:28", updated_at: "2013-09-19 16:37:28"
>
irb(main):006:0> b = Patient.birthday
irb(main):007:0> d = c.birthday
=> Thu, 29 Jun 1961
irb(main):009:0> month = d.month
=> 6
irb(main):010:0> day = d.mday
=> 29
irb(main):011:0> year = Date.today.year
=> 2013
irb(main):012:0> neu = Date.new(year,month,day)
=> Sat, 29 Jun 2013
You are trying to instantiate a Date object with invalid parameters, e.g.
Date.new(2013,99,1)
# => ArgumentError: invalid date
You problem is most likely not the code presented above, but the data you are inserting. Check your database for records that have invalid dates.
You can prevent such errors by presenting an error to the user upon submission when the date is invalid. In order to acheive that, you could add a validation rule to your model e.g.
class Patient < ActiveRecord::Base
validate :birthday, if:->(d){ Date.valid_date?(d) }
end

undefined method sitenum

I get a sitenum undefined method error. Problem is I am trying to target site_id and student_number and then increment value of student_number by 1 based on site_id. So there will be at least two records with a 2001 value for student_number if there are two site_ids (e.g. site_id 1, site_id 2). And if a value of 2001 exists for that site, then I would like to increment by 1 so next student_number for that site will be 2002, 2003, etc.
Student Model:
:student_number =>
sitenum = self.site_id
count = Student.count_by_sql("SELECT MAX(student_number) FROM students WHERE site_id = #{sitenum}")
if count >= 2001
Student.sitenum(:order => "student_number DESC").student_number + 1
else
2001
end
Any response would be greatly appreciated.
I understood nothing from a description, but suppose, you want this that way:
:student_number =>
sitenum = self.site_id
count = Student.count_by_sql("SELECT MAX(student_number) FROM students WHERE site_id = #{sitenum}")
if count >= 2001
Student(:condition => { :site_id => sitenum },
:order => "student_number DESC").student_number + 1
else
2001
end

Resources