简体   繁体   English

Ruby on Rails-总和计算不适用于模型中的关联

[英]Ruby on Rails - Sum calculation not working with associations in model

I have a User table with a column total_user_xp with a has_many :goals association. 我有一个用户表,该表具有带有has_many :goals关联的total_user_xp列。

The Goal table has a column total_goal_xp which is calculated in the model with the following method: 目标表具有一列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 

For some reason, in my controller and model file for User, I can't calculate the sum for total_goal_xp where the user_id matches the current_user. 由于某种原因,在我的User控制器和模型文件中,当user_id与current_user匹配时,我无法计算total_goal_xp的总和。 It always returns the value 0 as if the total_goal_xp wasn't being stored in the table. 它总是返回值0,就好像没有将total_goal_xp存储在表中一样。

I'm fairly new to rails but I have a feeling my total_goal_xp method isn't saving the value to the db. 我对Rails相当total_goal_xp但是我有一种感觉, total_goal_xp方法没有将值保存到db中。 It seems to recalculate the sum every time that method is called. 似乎每次调用该方法都会重新计算总和。 That said, in the rails console, running Goal.all gives me a table which does have the correct values so I don't understand why the following methods return the value 0. 就是说,在Rails控制台中,运行Goal.all给了我一张表,该表确实具有正确的值,所以我不明白为什么以下方法返回值0。

user_controller.rb user_controller.rb

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

user.rb user.rb

has_many :goals

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

In the server log, I get the following SQL - SELECT SUM("goals"."total_goal_xp") FROM "goals" WHERE "goals"."user_id" = ? [["user_id", 1]] 在服务器日志中,获得以下SQL- SELECT SUM("goals"."total_goal_xp") FROM "goals" WHERE "goals"."user_id" = ? [["user_id", 1]] SELECT SUM("goals"."total_goal_xp") FROM "goals" WHERE "goals"."user_id" = ? [["user_id", 1]] for both methods. 两种方法都为SELECT SUM("goals"."total_goal_xp") FROM "goals" WHERE "goals"."user_id" = ? [["user_id", 1]]

I know I shouldn't be doing the calculations in the controller but at the moment, I just want to get the calculation to work so I know the associations are working. 我知道我不应该在控制器中进行计算,但是此刻,我只想让计算正常工作,所以我知道关联正在正常工作。

Would appreciate any advice on the best practice for saving the total_goal_xp and the doing the same for the total_user_xp. 希望获得关于保存total_goal_xp的最佳实践的任何建议,以及对total_user_xp进行相同操作的建议。

Let me know if you'd like to see any other files. 如果您要查看其他文件,请告诉我。

Firstly, you have defined method name same as attribute/column name, that's a conflict. 首先,您定义了与属性/列名称相同的方法名称,这是一个冲突。 Secondly, if you want to calculate the total on the go, you don't need those columns. 其次,如果您要随时计算总数,则不需要这些列。

One way I would solve this as the columns are present, set the total value when the values are changed using callback mentioned in this answer 当列存在时,我将解决此问题的一种方法是,使用此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

OR you don't even need to recalculate sum everytime 否则您甚至不需要每次都重新计算总和

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

Now you don't need those methods and also, when displaying the data, there's no query hit to the db.. 现在,您不再需要这些方法,并且在显示数据时,也不会查询数据库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM