gpt4 book ai didi

ruby-on-rails - NoMethodError at/calculate undefined method `id' for nil :NilClass in Rails Appilcation

转载 作者:太空宇宙 更新时间:2023-11-03 16:45:14 25 4
gpt4 key购买 nike

我继承了一个 Rails 应用程序,我应该对其进行调试并开始运行,但问题是我对 Rails 并不熟悉。我已经对这里和其他地方的错误进行了研究,但我仍然不知道如何解决这个错误。

这是我的计算模型的代码

class Calculation < ActiveRecord::Base
belongs_to :user
has_many :calculation_expenses, dependent: :delete_all
has_many :user_account_stats, dependent: :delete_all
accepts_nested_attributes_for :calculation_expenses

def self.calculate_for(user, period = 'weeks', periods_count = 5*53 - 1)
user_accounts = {}
checking_ids = []
total_checking = 0
total_expense_per_account = {}
user.user_accounts.each do |ua|
total_expense_per_account[ua.id] = 0
user_accounts[ua.id] = ua.amount
if ua.is_checking?
checking_ids << ua.id
total_checking = total_checking + ua.amount
end
end

monthly = false
monthly = true if period == 'months'
user.user_account_stats.where('calculations.is_monthly = ?', monthly).delete_all
user.calculation_expenses.where('calculations.is_monthly = ?', monthly).delete_all
IncomeStat.where('income_id IN (?)', user.incomes.map(&:id)).delete_all
user.calculations.where(is_monthly: monthly).delete_all

calcs = []
calcs_expenses = []
accounts_stats = []
income_stats = []
left_to_bugdet = []
expenses = user.expenses.to_a
incomes = user.incomes.where(is_system: false).to_a
system_income_id = user.incomes.where(is_system: true).first.id
goals = user.expenses.where(is_goal: true).reorder('rank_of_priority ASC').to_a
goal_ids = goals.map(&:id)
current_goals_balance = {}
current_expenses_total = {}
goal_payments_made = {}
goal_monthly_override = {} #using this for loan payments with extra payed sum
loan_pay_off = {}
expenses_monthly = {}

expenses.each do |expense|
current_expenses_total[expense.id] = 0
expenses_monthly[expense.id] = expense.amount
end

start_dt = Date.today
start_dt += 1 + ((5 - start_dt.wday) % 7)

# firstly we need to calculate all incomes and expenses
for i in 0..periods_count
week_start = start_dt + i.send(period)
week_end = week_start + 1.send(period) - 1.day
total_income = 0
total_expense = 0
current_expenses = {}
scheduled_expenses = {}
expense_per_account = {}
user_accounts.each_pair do |key, amount|
expense_per_account[key] = 0
end

incomes.each do |income| #add incomes
cnt = income.exists_between week_start, week_end
income_amount = cnt * income.amount
total_income = total_income + income_amount
income_stats << [income_amount, income.id]
user_accounts[income.user_account_id] = user_accounts[income.user_account_id] + income_amount
if checking_ids.include? income.user_account_id
total_checking = total_checking + income_amount
end
end
income_stats << [0, system_income_id]

expenses.each do |expense| #substract expenses
cnt = expense.exists_between week_start, week_end
scheduled_expenses[expense.id] = (cnt > 0)
goal_payments_made[expense.id] ||= 0
goal_payments_made[expense.id] = goal_payments_made[expense.id] + cnt
ea = expense.amount
ea = goal_monthly_override[expense.id] unless goal_monthly_override[expense.id].nil?
expense_amount = cnt * ea
if expense.is_loan? && cnt > 0
loan_pay_off[expense.id] ||= 0
if expense.get_debt_sum - loan_pay_off[expense.id] < expense_amount
expense_amount = (expense.get_debt_sum - loan_pay_off[expense.id]) * (1 + expense.interest / Frequency.get_interest_amount(expense.frequency_id) / 100.0)
end
loan_pay_off[expense.id] = loan_pay_off[expense.id] + expense.get_main_part(loan_pay_off[expense.id], expense_amount)
end

if checking_ids.include? expense.user_account_id
total_expense = total_expense + expense_amount
end
user_accounts[expense.user_account_id] = user_accounts[expense.user_account_id] - expense_amount
current_expenses[expense.id] = expense_amount
expense_per_account[expense.user_account_id] = expense_per_account[expense.user_account_id] + expense_amount
if checking_ids.include? expense.user_account_id
total_checking = total_checking - expense_amount
end
current_expenses_total[expense.id] = current_expenses_total[expense.id] + expense_amount
total_expense_per_account[expense.user_account_id] = total_expense_per_account[expense.user_account_id] + expense_amount
end

extra_money = total_checking - user.minimum_safety_level
j = i - 1
while extra_money < 0 && j > 0 do #respect minimum safety level by reducing extra money levels on previous periods
reduce_extra = -extra_money
if calcs[j][5] < reduce_extra
reduce_extra = calcs[j][5]
end
calcs[j][5] = calcs[j][5] - reduce_extra
extra_money = extra_money + reduce_extra
calcs[i]
j = j - 1
end
extra_money = 0 if extra_money < 0

calcs << [week_end, user.id, total_income, total_expense, monthly, extra_money]

current_expenses.each_pair do |expense_id, budgeted|
calcs_expenses << [expense_id, budgeted, nil, current_expenses_total[expense_id], loan_pay_off[expense_id] || 0, scheduled_expenses[expense_id], expenses_monthly[expense_id]]
end
a = [] #temporary save stats
user_accounts.each_pair do |user_account_id, amount|
a << [user_account_id, amount, amount, expense_per_account[user_account_id], nil, total_expense_per_account[user_account_id]]
end
accounts_stats << a
end

extra_payments_data = []
accounts_stats = accounts_stats.map { |a| a }.sum
self.save_data(user, monthly, expenses.size, calcs, calcs_expenses, extra_payments_data, accounts_stats, income_stats)

#find last calculation without extra money
last_zero = Calculation.where(user_id: user.id, is_monthly: monthly, extra_money: 0).reorder('dt DESC').first
## remove local extra money before last zero - we cannot spend them
unless last_zero.nil?
Calculation.where(user_id: user.id, is_monthly: monthly).where('id < ?', last_zero.id).update_all extra_money: 0
# # find an extra money we can spend
em_count = Calculation.where(user_id: user.id, is_monthly: monthly).where('extra_money > 0').count
g = 0
id = 0
while em_count > 0 && g < periods_count - 1 do
calc = Calculation.where(user_id: user.id, is_monthly: monthly).where('extra_money > 0 AND id > ?', id).reorder('extra_money ASC').first
unless calc.nil?
goals.each do |goal|
unless goal.ends_before? calc.dt
ce = calc.calculation_expenses.where(expense_id: goal.id).first
amount = goal.aggressiveness / 100.0 * calc.extra_money
goal_left = goal.get_debt_sum - ce.paid_off
amount = goal_left if goal_left < amount
if amount > 0
ce.update_budgeted ce.budgeted + amount
end
end
end
g = g + 1
puts "#{g} of #{periods_count}"
id = calc.id
#find last calculation without extra money
last_zero = Calculation.where(user_id: user.id, is_monthly: monthly, extra_money: 0).reorder('dt DESC').first
# remove local extra money before last zero - we cannot spend them
Calculation.where(user_id: user.id, is_monthly: monthly).where('id < ?', last_zero.id).update_all extra_money: 0
else
g = periods_count
end
end
end
end

def self.save_data(user, monthly, expenses_count, calcs, calcs_expenses, extra_payments_data, accounts_stats, income_stats, dt = nil)
# write calculations to database
Calculation.import([:dt, :user_id, :total_income, :total_expense, :is_monthly, :extra_money], calcs, validate: false)
# write calculation ids to arrays
if dt.nil?
ids = user.calculations.where(is_monthly: monthly).pluck(:id)
else
ids = user.calculations.where(is_monthly: monthly).where('dt >= ?', dt).pluck(:id)
end
cur_ind = 0
cur_ind2 = 0
cur_ind3 = 0
num = expenses_count
num2 = user.incomes.count
num3 = user.user_accounts.size
ids.each_with_index do |id, ind|
num.times do
calcs_expenses[cur_ind] << ids[ind]
cur_ind = cur_ind + 1
end
num2.times do
income_stats[cur_ind2] << ids[ind]
cur_ind2 = cur_ind2 + 1
end
num3.times do
accounts_stats[cur_ind3] << ids[ind]
cur_ind3 = cur_ind3 + 1
end
end
# write all data with 2 queries
UserAccountStat::import([:user_account_id, :amount, :initial_amount, :budgeted, :actual, :total, :calculation_id], accounts_stats, validate: false)
CalculationExpense::import([:expense_id, :budgeted, :actual, :total, :paid_off, :is_scheduled, :monthly_payment, :calculation_id], calcs_expenses, validate: false)
IncomeStat::import([:amount, :income_id, :calculation_id], income_stats, validate: false)
user.expenses_groups.each do |group|
group.calculate_data
end
end

def as_json(options)
{
id: self.id,
total_income: self.total_income,
total_expense: self.total_expense,
extra_money: self.extra_money,
dt: self.dt
}
end
end

这是我的计算 Controller

class CalculationsController < ApplicationController
def index
unless current_user.calculations.any?
redirect_to '/calculate'
end
end

def load
respond_to do |format|
format.json { render json: get_data }
end
end

def calc
Calculation.calculate_for(current_user)
redirect_to calculations_path
end

def update
@calc = current_user.calculation_expenses.where(id: params[:id]).first
@calc.update_actual params[:value]
respond_to do |format|
format.json { render json: get_data }
end
end

def update_budgeted
@calc = current_user.calculation_expenses.where(id: params[:id]).first
@calc.update_budgeted params[:value]
respond_to do |format|
format.json { render json: get_data }
end
end

def group
if params[:id].blank?
@group = ExpensesGroup.create(name: params[:name], user_id: current_user.id)
else
@group = current_user.expenses_groups.where(id: params[:id]).first
unless @group.nil?
@group.update_attribute :name, params[:name]
end
end
end
end

当我在本地运行应用程序时,我可以看到问题出在计算模型中的 calculate_for 方法中的这一行

system_income_id = user.incomes.where(is_system: true).first.id

并在计算控件的cal方法中加上这一行

Calculation.calculate_for(current_user)

这是来自 rails 控制台的错误日志

NoMethodError - undefined method `id' for nil:NilClass:
app/models/calculation.rb:36:in `calculate_for'
app/controllers/calculations_controller.rb:16:in `calc'
actionpack (4.2.3) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.2.3) lib/abstract_controller/base.rb:198:in `process_action'
actionpack (4.2.3) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.2.3) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.2.3) lib/active_support/callbacks.rb:115:in `call'
activesupport (4.2.3) lib/active_support/callbacks.rb:553:in `block (2 levels) in compile'
activesupport (4.2.3) lib/active_support/callbacks.rb:503:in `call'
activesupport (4.2.3) lib/active_support/callbacks.rb:88:in `run_callbacks'
actionpack (4.2.3) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (4.2.3) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.2.3) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (4.2.3) lib/active_support/notifications.rb:164:in `block in instrument'
activesupport (4.2.3) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.2.3) lib/active_support/notifications.rb:164:in `instrument'
actionpack (4.2.3) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.2.3) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
activerecord (4.2.3) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.2.3) lib/abstract_controller/base.rb:137:in `process'
actionview (4.2.3) lib/action_view/rendering.rb:30:in `process'
actionpack (4.2.3) lib/action_controller/metal.rb:196:in `dispatch'
actionpack (4.2.3) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.2.3) lib/action_controller/metal.rb:237:in `block in action'
actionpack (4.2.3) lib/action_dispatch/routing/route_set.rb:76:in `dispatch'
actionpack (4.2.3) lib/action_dispatch/routing/route_set.rb:45:in `serve'
actionpack (4.2.3) lib/action_dispatch/journey/router.rb:43:in `block in serve'
actionpack (4.2.3) lib/action_dispatch/journey/router.rb:30:in `serve'
actionpack (4.2.3) lib/action_dispatch/routing/route_set.rb:821:in `call'
meta_request (0.3.0) lib/meta_request/middlewares /app_request_handler.rb:13:in `call'
rack-contrib (1.1.0) lib/rack/contrib/response_headers.rb:17:in `call'
meta_request (0.3.0) lib/meta_request/middlewares/headers.rb:16:in `call'
meta_request (0.3.0) lib/meta_request/middlewares /meta_request_handler.rb:13:in `call'
warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
warden (1.2.3) lib/warden/manager.rb:34:in `call'
rack (1.6.4) lib/rack/etag.rb:24:in `call'
rack (1.6.4) lib/rack/conditionalget.rb:25:in `call'
rack (1.6.4) lib/rack/head.rb:13:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/flash.rb:260:in `call'
rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/cookies.rb:560:in `call'
activerecord (4.2.3) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.2.3) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
activerecord (4.2.3) lib/active_record/migration.rb:377:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.2.3) lib/active_support/callbacks.rb:84:in `run_callbacks'
actionpack (4.2.3) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/reloader.rb:73:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
web-console (2.2.1) lib/web_console/middleware.rb:39:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.2.3) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.2.3) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.2.3) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.2.3) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.2.3) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.2.3) lib/rails/rack/logger.rb:20:in `call'
quiet_assets (1.1.0) lib/quiet_assets.rb:27:in `call_with_quiet_assets'
actionpack (4.2.3) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
rack (1.6.4) lib/rack/runtime.rb:18:in `call'
activesupport (4.2.3) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
actionpack (4.2.3) lib/action_dispatch/middleware/static.rb:116:in `call'
rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
railties (4.2.3) lib/rails/engine.rb:518:in `call'
railties (4.2.3) lib/rails/application.rb:165:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
rack (1.6.4) lib/rack/content_length.rb:15:in `call'
rack (1.6.4) lib/rack/handler/webrick.rb:88:in `service'
/home/xwattsh/.rbenv/versions/2.2.3/lib/ruby/2.2.0/webrick /httpserver.rb:138:in `service'
/home/xwattsh/.rbenv/versions/2.2.3/lib/ruby/2.2.0/webrick /httpserver.rb:94:in `run'
/home/xwattsh/.rbenv/versions/2.2.3/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'

最佳答案

=>这条线不安全:

system_income_id = user.incomes.where(is_system: true).first.id

当is_system设置为true,用户没有收入时会抛出异常。

您可以检查 .first 是否为 nil,或者将其放在 try/catch block 中。无论哪种情况,都取决于您如何处理 .first 不存在的情况。

例如。

first_system_income = user.incomes.where(is_system: true).first

if first_system_income.present?
//do your normal stuff here
else
//handle the exception case
end

或(不推荐)

begin
system_income_id = user.incomes.where(is_system: true).first.id
rescue => e
//handle the exception case
puts e
end

另外,这是一种方法中的一些严肃逻辑!既然您继承了该项目,那么一些评论或重构可能会有所帮助:)

关于ruby-on-rails - NoMethodError at/calculate undefined method `id' for nil :NilClass in Rails Appilcation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34448375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com