I currently am working on my first rails project after working through multiple tutorials.
I am trying to build a webpage to track my savings goal for the next 6 months.
essentially the site consists of a form input where I input the date I put money into savings and the amount. This site then updates a line graph to show the current savings vs. the goal line.
So far I have successfully built the form and database (using postgresql) and have created the chart which displays the goal and accepts input from the form.
The problem I have is that the input values are displaying as discrete numbers and not a cumulative sum up that month (i.e. week 4 should be the sum of savings from weeks 1 to 4).
I considered initially having a 3rd column in the db called amount_cum and put some lines in the page load method in the controller, that means the database would recalculate at each page load which may be slow...
Any advise would be appreciated, should I be looking to modify the model or the controller?
Lay on the wise words
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
And model file:
class Pages < ActiveRecord::Base
validates :week, presence: true
validates :amount, presence: true
end
my view file - I use chartkick gem to generate the chart:
<%= line_chart [
{name: "Amount Saved", data: @progress.group(:week).sum(:amount)},
{name: "Goal Savings", data: @goal.group(:week).sum(:amount) }] %>
Screen shot of the application so you can see how the graph is to be displayed against the goal. link
In that case, you could use inject
in the view when generating the chart:
<% 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) }]
%>
Shorter but a little awkward:
<% 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) }]
%>
You didn't post any info on the Goal
model, but you could use a similar technique if you are also looking to plot the incremental increase in the goal each week.
EDIT: If you need an array of arrays, you could try something like this (forgive me, I'm doing this on my phone)
<% @progress.inject(0) { |sum, page| (saved << [page.week, sum + page.amount]).last.last} %>
EDIT 2:
I don't think inject
should modify the original @progress array (if that's what you're asking), but for the sake of argument (and diagnostics), try the following (we can certainly pretty this up if it works):
<% 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) }]
%>