如何使用 rails 将一条记录中多列的计算结果更新到 postgresql 数据库中

how to update a computed result of several columns in one record into postgresql database with rails

我有一个名为 "Scores" 的 table,它有 4 列,"first"、"second"、"third" 和 "average" 用于保存用户评分记录。

当用户最初创建记录时,他可以将 "average" 列留空。然后他可以稍后编辑所有 3 个乐谱。

编辑后,用户可以在他的显示页面中看到计算的平均值(或总和,或任何计算结果。),因为我有

默认显示 @ave = (@score.first + @score.second + @score.third)/3 结束

但是,@ave 不在数据库中,如何将@ave 更新到我数据库的"average" 列中?

  1. 理想情况下,最好在更新到数据库之前进行计算,这样4个值可以一起更新到数据库。它可能与活动记录回调有关,但我不知道该怎么做。

  2. 第二种方法,我想我需要在数据库中有一个 "trigger" 以便它可以在其他 3 列更新后立即计算和更新 "average" 列。如果您是这样做的,请告诉我与解决方案 1 相比的优势。

  3. 最后一种方法,因为用户已经知道他的显示页面中的平均值,所以我不必立即将计算出的平均值更新到 "average" 列中。我想我可以把它留给 delayed_job 或后台工作。如果你是这样做的,请告诉我怎么做。

提前致谢!(ruby 2.3, rails 5.0.1, postgresql 9.5

想法 1 和 2 是完全有效的方法。想法 3 有点矫枉过正,我强烈建议不要采用这种方法。

在想法 1 中,您需要做的(使用任何语言)只需查看输入的每个单独值(不包括平均值)并生成要包含在插入语句中的平均值。就这么简单。

想法2需要触发如下:

 CREATE OR REPLACE FUNCTION update_average()
   RETURNS trigger AS
 $BODY$
 BEGIN
  NEW.AVERAGE=(NEW.first+NEW.second+NEW.third)/3;
  RETURN NEW;
 END;
 $BODY$

然后在更新或插入 table 时将其分配给 运行:

 CREATE TRIGGER last_name_changes
   BEFORE INSERT or UPDATE
   ON scores
   FOR EACH ROW
   EXECUTE PROCEDURE update_average();

除非您出于某种原因确实需要存储在数据库中的平均值,否则我会向 Score 模型添加一个属性:

def average
  (first + second + third)/3.0
end

如果一个或多个可能不存在,我会:

def average
  actual_scores = [first, second, third].compact
  return nil if actual_scores.empty?
  actual_scores.sum / actual_scores.size
end

如果您确实需要保存平均值,那么我会添加一个 before_validate 回调:

before_validation do
  self.average = (first + second + third)/3.0
end