【问题标题】:Ruby on Rails - Sum calculation not working with associations in modelRuby on Rails - 总和计算不适用于模型中的关联
【发布时间】:2023-03-28 01:55:02
【问题描述】:

我有一个用户表,其中有一列 total_user_xphas_many :goals 关联。

目标表有一个列total_goal_xp,在模型中使用以下方法计算:

# goal.rb

  belongs_to :user
  has_many :goal_activities
  has_many :activities, through: :goal_activities

def total_goal_xp
    self.total_goal_xp = self.goal_activities.sum(:total_xp)
end 

由于某种原因,在我的用户控制器和模型文件中,我无法计算 user_id 与 current_user 匹配的 total_goal_xp 的总和。它总是返回值 0,就好像 total_goal_xp 没有存储在表中一样。

我对 Rails 还很陌生,但我感觉我的 total_goal_xp 方法没有将值保存到数据库中。每次调用该方法时似乎都会重新计算总和。也就是说,在 Rails 控制台中,运行 Goal.all 会为我提供一个具有正确值的表,所以我不明白为什么以下方法返回值 0。

user_controller.rb

def show
    @user_goals = current_user.goals.all
    @user_xp = @user_goals.sum(:total_goal_xp)
end

用户.rb

has_many :goals

def set_total_user_xp
  goal = self.goals.all
  self.total_user_xp = goal.sum(:total_goal_xp)
end

在服务器日志中,我得到以下 SQL - SELECT SUM("goals"."total_goal_xp") FROM "goals" WHERE "goals"."user_id" = ? [["user_id", 1]] 两种方法。

我知道我不应该在控制器中进行计算,但目前我只想让计算工作,所以我知道关联正在工作。

对于保存 total_goal_xp 的最佳实践以及对 total_user_xp 执行相同操作的任何建议,我们将不胜感激。

如果您想查看其他文件,请告诉我。

【问题讨论】:

  • 评论total_goal_xp方法,看看它是否返回正确的值
  • 我删除了total_goal_xp 方法,刷新了显示current_uder.total_user_xp 的页面,但它仍然给我值0。这是total_user_xp 方法-self.goals.sum(:total_goal_xp)。 SQL 也没有改变。不过重新加载了控制台,total_goal_xp 列现在显然是空白的,所以 0 将是正确的值。这是你要我做的吗?
  • 尝试了另一种方法self.goals.sum(:xp),总和效果很好。 xp 是用户保存的输入,不是计算。看起来我无法访问 User 模型中的 total_goal_xp 方法,即使我在那里有关联并且在 Goal 表中有 user_id。你上次提到初始化。这是我这次需要做的事情吗?

标签: mysql ruby-on-rails activerecord associations


【解决方案1】:

首先,您定义的方法名称与属性/列名称相同,这是一个冲突。 其次,如果您想随时随地计算总数,则不需要这些列。

当列存在时,我可以解决这个问题的一种方法,当值发生更改时使用answer中提到的回调设置总值

def set_total_xp
  goal_activity = self.goal_activities.where(goal_id: goal_id).first_or_initialize
  goal_activity.update_attribute(:total_xp, (quantity*goal.xp))
  goal = Goal.find_by_id(goal_id)
  user = goal.user
  goal.update_attribute(:total_goal_xp, goal.goal_activities.sum(:total_xp))
  user.update_attribute(:total_user_xp, user.goals.sum(:total_goal_xp))
end

或者你甚至不需要每次都重新计算总和

def set_total_xp
  goal_activity = self.goal_activities.where(goal_id: goal_id).first_or_initialize
  goal_activity.update_attribute(:total_xp, (quantity*goal.xp))
  goal = Goal.find_by_id(goal_id)
  xp = goal_activity.total_xp
  goal.update_attribute(:total_goal_xp, (goal.total_goal_xp + xp))
  goal.user.update_attribute(:total_user_xp, (user.total_user_xp + xp))
end

现在您不需要这些方法,而且在显示数据时,数据库没有查询命中..

【讨论】:

  • 谢谢,我需要对关联进行任何更改吗?我收到一条错误消息NoMethodError (undefined method 'includes' for #<Goal:0x007fa9f08e0638>):。以下是目前的关联 - Activity: belongs_to :goal, has_many :goal_activities GoalActivity: belongs_to :goal, :activity Goal: belongs_to :user, has_many :goal_activities, has_many :activities, through: :goal_activities User: has_many :goals
  • 尝试从goaluser这两个对象中删除includes
  • 检查替代解决方案
  • 再次感谢@Md。 FarhanMemon,非常感谢您的帮助。
猜你喜欢
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多