I have a method/action/piece of code (I always get a bit lost on the terminology of rails) set up in my model to update the amount remaining in a budget when I input a new advert.
class Budget < ActiveRecord::Base
belongs_to :client
has_many :adverts
before_save :update_budget
validates :name, :amount, :client_id, presence: true
def update_budget
self.amount_remaining = self.amount - self.amount_spent
end
end
This works fine when updating my budgets or entering a new advert. Everything works as it should. However, I have written a rake task to write a list of recurring budgets to the budget table (so I can schedule it monthly). However, when I run this task from the terminal it runs into an error.
The rake task.
desc "Recurring Updates"
task :recurring_budgets => :environment do
@recurring_budgets = RecurringBudget.all
@recurring_budgets.each do |recurring_budget|
Budget.create(name: recurring_budget.name, amount: recurring_budget.amount, client_id: recurring_budget.client_id)
end
end
The error.
$ rake recurring_budgets
rake aborted!
TypeError: nil can't be coerced into Fixnum
/Users/tomgamon/projects/adsman/app/models/budget.rb:9:in `-'
/Users/tomgamon/projects/adsman/app/models/budget.rb:9:in `update_budget'
/Users/tomgamon/projects/adsman/lib/tasks/recurring_budgets.rake:6:in `block (2 levels) in <top (required)>'
/Users/tomgamon/projects/adsman/lib/tasks/recurring_budgets.rake:5:in `block in <top (required)>'
Tasks: TOP => recurring_budgets
(See full trace by running task with --trace)
Worth noting is when I remove the method from my model, the task writes to the budgets table fine.
Anyone have any ideas?
This is due to you were trying to minus
nil
from amount
update_budget
called in before_save callback
- and here you calculating amount_remaining
with subtracting amount_spent
from amount
in your case amount_spent
is nil
, so when you try subtracting nil
value from something then you will get this error - TypeError: nil can't be coerced into Fixnum
There are two solutions for this -
1 - if amount_spent
is nil
you have to use 0
def update_budget
self.amount_remaining = self.amount - (self.amount_spent || 0)
end
OR
2 - you can set default values for amount_remaining
, amount
and amount_spent
as 0
(Zero) in migration.
It will be better to set default values for such fields instead of checking nil
values in code.