【问题标题】:Rails running total columnRails 运行总列
【发布时间】:2017-01-06 08:05:12
【问题描述】:

在完成了多个教程之后,我目前正在开发我的第一个 Rails 项目。

我正在尝试建立一个网页来跟踪我未来 6 个月的储蓄目标。

基本上该网站由一个表单输入组成,我在其中输入我将钱存入储蓄的日期和金额。然后,此网站会更新折线图以显示当前节省与目标线的关系。

到目前为止,我已经成功构建了表单和数据库(使用 postgresql)并创建了显示目标并接受来自表单的输入的图表。

我遇到的问题是输入值显示为离散数字,而不是当月的累积总和(即第 4 周应该是第 1 周到第 4 周节省的总和)。

我最初考虑在数据库中有一个名为 amount_cum 的第三列,并在控制器的页面加载方法中添加了一些行,这意味着数据库将在每个页面加载时重新计算,这可能会很慢......

任何建议都将不胜感激,我应该修改模型还是控制器?

讲道理

class PagesController < ApplicationController
def home
 @pages = Pages.new
 @progress = Pages.order(:week)
 @goal = Goals.all
end

def create
 @pages = Pages.new(pages_params)
 weeks_year=Date.parse(params[:pages][:week]).strftime("%U")

 @pages = Pages.new(pages_params.merge(:week => weeks_year))


if @pages.save
  flash[:success]="Savings Uploaded Successfully"
   redirect_to root_path
else
   flash[:danger]=@pages.errors.full_messages.join(", ")
   redirect_to root_path
 end
 end  
private
 def pages_params
 params.require(:pages).permit(:week, :amount)
end

end

和模型文件:

 class Pages < ActiveRecord::Base
  validates :week, presence: true
  validates :amount, presence: true
 end

我的视图文件 - 我使用 chartkick gem 生成图表:

  <%= line_chart [
  {name: "Amount Saved", data: @progress.group(:week).sum(:amount)},
  {name: "Goal Savings", data: @goal.group(:week).sum(:amount) }] %>

应用程序的屏幕截图,以便您查看图表是如何针对目标显示的。 link

【问题讨论】:

  • 如果您可以发布一些代码 sn-ps 可能会更容易提供帮助
  • 已添加 - 对我轻松一点:P
  • 所以你需要按月累积总和?
  • 在这个阶段,我使用周作为我的 x 轴,所以我将日期转换为一年中的一周。在我的脑海中,我要么希望控制器执行数据库中所有条目的总和,其周值小于当前对象,然后将该数字保存到数据库中,要么有一个第三列是运行总计。哪个更容易实现

标签: ruby-on-rails database postgresql cloud9-ide


【解决方案1】:

在这种情况下,您可以在生成图表时在视图中使用inject:

<% saved = [] %>
<% @progress.inject(0) do |sum, page| %>
<%   current = sum + page.amount
<%   saved << current %>
<%   current # the return value is passed in as `sum` in the next iteration %>
<% end %>
<%= line_chart [
      {name: "Amount Saved", data: saved},
      {name: "Goal Savings", data: @goal.group(:week).sum(:amount) }]
%>

较短但有点尴尬:

<% saved = [] %>
<% @progress.inject(0) { |sum, page| (saved << sum + page.amount).last} %>
<%= line_chart [
      {name: "Amount Saved", data: saved},
      {name: "Goal Savings", data: @goal.group(:week).sum(:amount) }]
%>

您没有在 Goal 模型上发布任何信息,但如果您还希望绘制每周目标的增量增量,则可以使用类似的技术。

编辑: 如果你需要一个数组数组,你可以试试这样的(原谅我,我在手机上做这个)

<% @progress.inject(0) { |sum, page| (saved << [page.week, sum + page.amount]).last.last} %>

编辑 2: 我不认为inject 应该修改原始的@progress 数组(如果这就是您要问的),但是为了争论(和诊断),请尝试以下操作(如果它有效,我们当然可以完善它) :

<% saved = [] %>
<% cum_sum = 0 %>

<% @progress.map do |page| %>
<%   cum_sum += page.amount %>
<%   saved << [page.week, cum_sum] %>
<% end %>
<%= line_chart [
      {name: "Amount Saved", data: saved},
      {name: "Goal Savings", data: @goal.group(:week).sum(:amount) }]
%>

【讨论】:

  • 刚刚尝试过 - 在循环中使用 line_chart 函数会导致它为每次迭代生成一个新图形(我的页面上现在大约有 50 个图形)。
  • 还有一种使用自定义 SQL 的方法(selecting 正在运行的总列),但我不确定它会更清晰或更高效。
  • 我明白了。尝试最新版本。
  • 我很抱歉,电池几乎没电了,没有充电器,做得很快,但应该是要点。但是没有保证 ;-)
  • 鉴于我们现在只是生成一个新的数据数组来提供给图表,将大部分代码移动到模型中可能更有意义,或者可能是一个助手。明天我拿到充电器后会再看看;-)
【解决方案2】:

在 Rails 中有一种更简单的方法来计算总和 - 您不必使用 inject,只需在记录数组上调用 sum。在你的情况下,它会是这样的:

@progress.sum(:amount)

但是,我在第一次阅读时解释您的问题的方式是,我认为您试图从一组实际总和中创建一个部分总和数组。我不知道这对你有没有用,但无论如何,这就是我使用 Ruby 的 each_with_object 和 with_index 和 Rails 的 sum 的方法:

amounts = [100, 200, 150, 300, 120]

partial_sums = amounts.each_with_object([]).with_index do |(_, obj), i|
  obj << amounts[0..i].sum
end                      # => [100, 300, 450, 750, 870]

# Examples:
partial_sums[0]  = 100  # 1st sum - just the first element
partial_sums[2]  = 450  # 3rd partial sum
partial_sums[-1] = 870  # the total of all the amounts from the array

希望你觉得这很有用。

【讨论】:

  • 这可以和哈希一起使用吗?抱歉无知,但你将如何修改它以应用于键值对,因为我仍然需要每个累积总和都有一个键:weeks,所以我可以将两者绘制成折线图
猜你喜欢
  • 2021-07-26
  • 1970-01-01
  • 2018-01-12
  • 2016-02-21
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 2023-03-03
相关资源
最近更新 更多