【Ruby on Rails開発奮闘記】シンプルな家計簿アプリを作る(3)

こんにちは、koheiです。
前回の記事では、収支登録機能を追加しましたので、今回は収支データを確認する機能を作成します。
※前回の記事は、以下です。
- シンプルな家計簿アプリを作る(1) 「科目設定機能を作る」
- シンプルな家計簿アプリを作る(2) 「収支登録機能を作る」
- シンプルな家計簿アプリを作る(3) 「収支確認機能(グラフなど)を作る」←今回の内容
目次
1.仕様(今回追加する部分)
今回作成する部分は以下になります。収支確認画面を選択すると、月次収支確認と年間収支確認を選択でき、選択した月や年度に応じて、収支結果が表示されるようにします。なお、年間収支確認画面では、収支結果をグラフで表示するように対応します。

今回作成する部分のMVCモデルは以下のようになります。
モデルは、今回は新規で作成しません。収支結果を計算し、計算結果をビューやjavascriptへ渡すためのコントローラー「balance_confirm」を追加します。
グラフ描画は、javascriptで実現します。

2.月別収支確認を追加

まずは、以下コマンドを入力し、収支結果を計算するためのコントローラー「balance_confirm」を作成します。
各アクションへのパスを追加します。今回、topアクションとshowアクションを追加しました。
Rails.application.routes.draw do root "top#index" post "income_values/new(/:name)" => "income_values#new" post "fixedcost_values/new(/:name)" => "fixedcost_values#new" post "variablecost_values/new(/:name)" => "variablecost_values#new" get "balance_confirm" => "balance_confirm#top" post "balance_confirm/show(/:name)" => "balance_confirm#show" resources :incomes resources :fixedcosts resources :variablecosts resources :income_values resources :fixedcost_values resources :variablecost_values end
コントローラーにtopアクションとshowアクションを実装します。(※topアクションは特に計算などの処理がないので空です)
ビューから渡されたyear_month情報をもとに、各科目の実績データが入っている「IncomeValue」や「fixedcastValue」、「VariablecastValue」を取得し、収支結果を計算しています。
class BalanceConfirmController < ApplicationController
def top
end
def show
@year_month = params[:year_month] + "-01"
@incomes = Income.order(created_at: :asc)
@fixedcosts = Fixedcost.order(created_at: :asc)
@variablecosts = Variablecost.order(created_at: :asc)
#収入計算
@income_values =IncomeValue.where(year_month: @year_month)
@income_value_total = 0 #収入合計
@income_values.each do |income_value|
@income_value_total += income_value.value
end
#固定費計算
@fixedcost_values = FixedcostValue.where(year_month: @year_month)
@fixedcost_value_total = 0 #固定費合計
@fixedcost_values.each do |fixedcost_value|
@fixedcost_value_total += fixedcost_value.value
end
#変動費計算
@variablecost_values = VariablecostValue.where(year_month: @year_month)
@variablecost_value_total = 0 #変動費合計
@variablecost_values.each do |variablecost_value|
@variablecost_value_total += variablecost_value.value
end
#収支差
@balance_difference = @income_value_total - (@fixedcost_value_total + @variablecost_value_total)
end
end
収支確認用のtopビューとshowビューを作成します。
topビューでは、コントローラー側にわたす年月情報の入力画面を作成します。
showビューでは、コントローラー側で計算した収支結果を表示する処理を実装します。
<h2>月次収支確認</h2>
<%= form_tag({controller: :balance_confirm, action: :show}, {method: :post}) do %>
<input type="month" name="year_month">
<input type="submit">
<% end %>
<h2><%= @year_month %> 月次収支確認</h2> <h3>収入</h3> <% if @income_values.present? %> <table> <thead> <tr> <th>科目名</th> <th>値</th> <th>備考</th> </tr> </thead> <tbody> <% @income_values.each do |income_value| %> <tr> <td><%= @incomes.find(income_value.income_id).name %></td> <td style="text-align: right"><%= income_value.value %>円</td> <td><%= income_value.description %></td> </tr> <% end %> <tr> <td><b>収入合計</b></td> <td style="text-align: right"><b><%= @income_value_total %>円</b></td> <td></td> </tr> </tbody> </table> <% else %> <p>登録されている収入がありません。</p> <% end %> <h3>固定費</h3> <% if @fixedcost_values.present? %> <table> <thead> <tr> <th>科目名</th> <th>値</th> <th>備考</th> </tr> </thead> <tbody> <% @fixedcost_values.each do |fixedcost_value| %> <tr> <td><%= @fixedcosts.find(fixedcost_value.fixedcost_id).name %></td> <td style="text-align: right"><%= fixedcost_value.value %>円</td> <td><%= fixedcost_value.description %></td> </tr> <% end %> <tr> <td><b>固定費合計</b></td> <td style="text-align: right"><b><%= @fixedcost_value_total %>円</b></td> <td></td> </tr> </tbody> </table> <% else %> <p>登録されている固定費がありません。</p> <% end %> <h3>変動費</h3> <% if @variablecost_values.present? %> <table> <thead> <tr> <th>科目名</th> <th>値</th> <th>備考</th> </tr> </thead> <tbody> <% @variablecost_values.each do |variablecost_value| %> <tr> <td><%= @variablecosts.find(variablecost_value.variablecost_id).name %></td> <td style="text-align: right"><%= variablecost_value.value %>円</td> <td><%= variablecost_value.description %></td> </tr> <% end %> <tr> <td><b>変動費合計</b></td> <td style="text-align: right"><b><%= @variablecost_value_total %>円</b></td> <td></td> </tr> </tbody> </table> <h3>収支結果</h3> <table> <tbody> <tr> <td><b>収支差</b></td> <td style="text-align: right"><b><%= @balance_difference %>円</b></td> <td></td> </tr> </tbody> </table> <b>収支差:<%= @balance_difference %> 円</b> <% else %> <p>登録されている変動費がありません。</p> <% end %>
家計簿アプリのTOPページに、収支確認へのリンクを追加します。
<h1>Simple Kakeibo</h1> <p>シンプルな家計簿アプリです。</p> <h2>科目設定</h2> <ul> <li><%= link_to "収入科目設定", :incomes %></li> </ul> <ul> <li><%= link_to "固定費科目設定", :fixedcosts %></li> </ul> <ul> <li><%= link_to "変動費科目設定", :variablecosts %></li> </ul> <h2>収支登録</h2> <ul> <li><%= link_to "収入金額登録", :income_values %></li> </ul> <ul> <li><%= link_to "固定費金額登録", :fixedcost_values %></li> </ul> <ul> <li><%= link_to "変動費金額登録", :variablecost_values %></li> </ul> <h2>収支確認</h2> <ul> <li><%= link_to "収支確認画面", balance_confirm_path %></li> </ul>
3.年間収支確認を追加

続いて、年間の収支確認画面を作成します。
コントローラーに年間収支確認用のアクション「show_year」を追加します。
収入トータル、固定費、変動費のトータルを計算するサブ関数(cal_income_total,cal_fixedcost_total,cal_variablecost_total)を作成し、年間の収支結果を計算します。
(※サブ関数を作成した関係で、showアクションもサブ関数を使うように変更しています。)
class BalanceConfirmController < ApplicationController
def top
end
def show
@year_month = params[:year_month] + "-01"
@incomes = Income.order(created_at: :asc)
@fixedcosts = Fixedcost.order(created_at: :asc)
@variablecosts = Variablecost.order(created_at: :asc)
#収入計算
@income_values =IncomeValue.where(year_month: @year_month)
@income_value_total = cal_income_total(@income_values)
#固定費計算
@fixedcost_values = FixedcostValue.where(year_month: @year_month)
@fixedcost_value_total = cal_fixedcost_total(@fixedcost_values)
#変動費計算
@variablecost_values = VariablecostValue.where(year_month: @year_month)
@variablecost_value_total = cal_variablecost_total(@variablecost_values)
#収支差
@balance_difference = @income_value_total - (@fixedcost_value_total + @variablecost_value_total)
end
def show_year
year = params[:year]
@year = year
months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12" ]
year_months = months.map do |month|
year+"-"+month+"-01"
end
puts year_months
#年度の収入配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
year_months.each do |year_month|
income_values = IncomeValue.where(year_month: year_month)
if income_values.present?
total[i] = cal_income_total(income_values)
end
i += 1
end
@income_value_totals = total
#年度の固定費配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
year_months.each do |year_month|
fixedcost_values = FixedcostValue.where(year_month: year_month)
if fixedcost_values.present?
total[i] = cal_fixedcost_total(fixedcost_values)
end
i += 1
end
@fixedcost_value_totals = total
#年度の変動費配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
year_months.each do |year_month|
variablecost_values = VariablecostValue.where(year_month: year_month)
if variablecost_values.present?
total[i] = cal_variablecost_total(variablecost_values)
end
i += 1
end
@variablecost_value_totals = total
#年度の収支結果を計算
@balance_differences = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
0.upto(11) do |i|
if @income_value_totals[i].present?
@balance_differences[i] = @income_value_totals[i] - (@fixedcost_value_totals[i] + @variablecost_value_totals[i])
end
end
end
#収入トータル計算
def cal_income_total(income_values)
income_value_total = 0 #固定費合計
income_values.each do |income_value|
income_value_total += income_value.value
end
income_value_total
end
#固定費トータル計算
def cal_fixedcost_total(fixedcost_values)
fixedcost_value_total = 0 #固定費合計
fixedcost_values.each do |fixedcost_value|
fixedcost_value_total += fixedcost_value.value
end
fixedcost_value_total
end
#変動費トータル計算
def cal_variablecost_total(variablecost_values)
variablecost_value_total = 0 #変動費合計
variablecost_values.each do |variablecost_value|
variablecost_value_total += variablecost_value.value
end
variablecost_value_total
end
end
show_yearへのパスを追加します。
Rails.application.routes.draw do root "top#index" post "income_values/new(/:name)" => "income_values#new" post "fixedcost_values/new(/:name)" => "fixedcost_values#new" post "variablecost_values/new(/:name)" => "variablecost_values#new" get "balance_confirm" => "balance_confirm#top" post "balance_confirm/show(/:name)" => "balance_confirm#show" post "blance_confirm/show_year(/:name)" => "balance_confirm#show_year" resources :incomes resources :fixedcosts resources :variablecosts resources :income_values resources :fixedcost_values resources :variablecost_values end
年間収支確認用の「show_year」ビューを作成します。
コントローラーで計算した結果をテーブルで表示させます。
<h2><%= @year %>年 年間収支確認</h2> <table> <thead> <tr> <th>年月</th> <th>収入合計値</th> <th>固定費合計値</th> <th>変動費合計値</th> <th>収支(収入-費用)結果</th> </tr> </thead> <tbody> <% month=1 %> <% 0.upto(11) do |i| %> <% if @income_value_totals[i].present? %> <tr> <td><%= @year %>年<%= i+1 %>月</td> <td><%= @income_value_totals[i] %>円</td> <td><%= @fixedcost_value_totals[i] %>円</td> <td><%= @variablecost_value_totals[i] %>円</td> <td><%= @balance_differences[i] %>円</td> </tr> <% end %> <% end %> </tbody> </table>
収支確認ページに年間収支へのリンクを追加します。
<h2>月次収支確認</h2>
<%= form_tag({controller: :balance_confirm, action: :show}, {method: :post}) do %>
<input type="month" name="year_month">
<input type="submit">
<% end %>
<h2>年間収支確認</h2>
<%= form_tag({controller: :balance_confirm, action: :show_year}, {method: :post}) do %>
<input type="hidden" name="year">
<select name="year">
<% 2010.upto(2050) do |n| %>
<option value=<%= n.to_s %>><%= n %></option>
<% end %>
</select>
<input type="submit">
<% end %>
4.グラフ対応

4-1.Javascriptパッケージマネージャ「Yarn」をインストール
Ruby on Railsでグラフ描画は、Javascriptで行うため、まずJavascriptパッケージマネージャのYarnをインストールします。
4-2.必要なGemをインストール
グラフ描画はchart.jsというグラフ用のライブラリを使います。
Ruby on Railsでchart.jsを使用するには、「chart-js-rails」というGemパッケージを使います。
また、RailsのコントローラーからJavascriptへグラフデータをやり取りするため、「gon」パッケージをインストールします。
Gemfileに以下を追記します。
# Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.2' gem 'chart-js-rails', '~> 0.1.4' gem 'gon', '~> 6.2.0'
以下コマンドでインストールします。
4-3.chart.jsのインストール
package.jsonに以下を追加します。
{
"name": "sample_kakeibo",
"private": true,
"dependencies": {
"chart.js": "^2.7.1"
}
}
以下コマンドを入力しchart.jsをインストールします。
以下を追記し、ライブラリを読み込みます。
// //= require Chart.min //= require rails-ujs //= require activestorage //= require turbolinks //= require_tree .
4-4.グラフ実装
新規ファイルchart_sample.coffeeを作成し、グラフ実装部を以下のように実装します。
window.draw_graph = ->
ctx = document.getElementById("myChart").getContext('2d')
barNum = gon.data_incomes.length
labels = new Array(barNum)
incom_bgColors = new Array(barNum)
incom_bdColors = new Array(barNum)
fixed_bgColors = new Array(barNum)
fixed_bdColors = new Array(barNum)
variable_bgColors = new Array(barNum)
variable_bdColors = new Array(barNum)
result_bgColors = new Array(barNum)
result_bdColors = new Array(barNum)
for i in [0...gon.data_incomes.length]
labels[i] = i+1 +'月'
incom_bgColors[i] = 'rgba(135, 201, 164, 0.2)'
incom_bdColors[i] = 'rgba(135, 201, 164, 1)'
fixed_bgColors[i] = 'rgba(247, 176, 44, 0.2)'
fixed_bdColors[i] = 'rgba(247, 176, 44, 1)'
variable_bgColors[i] = 'rgba(233, 77, 55, 0.2)'
variable_bdColors[i] = 'rgba(233, 77, 55, 1)'
result_bgColors[i] = 'rgba(0, 134, 186, 0.2)'
result_bdColors[i] = 'rgba(0, 134, 186, 1)'
myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels
datasets: [{
label: '収入合計値',
data: gon.data_incomes,
backgroundColor: incom_bgColors,
borderColor: incom_bdColors,
borderWidth: 1
},{
label: '固定費合計値',
data: gon.data_fixedcosts,
backgroundColor: fixed_bgColors,
borderColor: fixed_bdColors,
borderWidth: 1,
type: 'bar'
},{
label: '変動費合計値',
data: gon.data_variablecosts,
backgroundColor: variable_bgColors,
borderColor: variable_bdColors,
borderWidth: 1,
type: 'bar'
},{
label: '収支結果合計値',
data: gon.data_results,
backgroundColor: result_bgColors,
borderColor: result_bdColors,
borderWidth: 1,
type: 'bar'
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
})
gonを使うため、application.html.erbに以下を追加します。
<!DOCTYPE html>
<html>
<head>
<title>SampleKakeibo</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= Gon::Base.render_data %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
gonを使って、コントローラー側からJavascriptにデータを渡します。
def show_year
year = params[:year]
@year = year
months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12" ]
year_months = months.map do |month|
year+"-"+month+"-01"
end
puts year_months
#年度の収入配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
gon.data_incomes = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil] #グラフ用データ
year_months.each do |year_month|
income_values = IncomeValue.where(year_month: year_month)
if income_values.present?
total[i] = cal_income_total(income_values)
gon.data_incomes[i] = total[i] #グラフ用データ
end
i += 1
end
@income_value_totals = total
#年度の固定費配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
gon.data_fixedcosts = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil] #グラフ用データ
year_months.each do |year_month|
fixedcost_values = FixedcostValue.where(year_month: year_month)
if fixedcost_values.present?
total[i] = cal_fixedcost_total(fixedcost_values)
gon.data_fixedcosts[i] = total[i] #グラフ用データ
end
i += 1
end
@fixedcost_value_totals = total
#年度の変動費配列を作成
i=0
total = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
gon.data_variablecosts = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil] #グラフ用データ
year_months.each do |year_month|
variablecost_values = VariablecostValue.where(year_month: year_month)
if variablecost_values.present?
total[i] = cal_variablecost_total(variablecost_values)
gon.data_variablecosts[i] = total[i] #グラフ用データ
end
i += 1
end
@variablecost_value_totals = total
#年度の収支結果を計算
@balance_differences = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
gon.data_results = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil] #グラフ用データ
0.upto(11) do |i|
if @income_value_totals[i].present?
@balance_differences[i] = @income_value_totals[i] - (@fixedcost_value_totals[i] + @variablecost_value_totals[i])
gon.data_results[i] = @balance_differences[i] #グラフ用データ
end
end
end
ビューにグラフ描画のスクリプトを読み込み処理を追加します。
<h2><%= @year %>年 年間収支確認</h2> <table> <thead> <tr> <th>年月</th> <th>収入合計値</th> <th>固定費合計値</th> <th>変動費合計値</th> <th>収支(収入-費用)結果</th> </tr> </thead> <tbody> <% month=1 %> <% 0.upto(11) do |i| %> <% if @income_value_totals[i].present? %> <tr> <td><%= @year %>年<%= i+1 %>月</td> <td><%= @income_value_totals[i] %>円</td> <td><%= @fixedcost_value_totals[i] %>円</td> <td><%= @variablecost_value_totals[i] %>円</td> <td><%= @balance_differences[i] %>円</td> </tr> <% end %> <% end %> </tbody> </table> <canvas id="myChart" width="400" height="400"></canvas> <script>draw_graph();</script>
以上で実装は完了です。
bin/rails sコマンドでサーバーを起動し、ブラウザでhttp://localhost:3000/にアクセスしてみてください。
以下のように、収支確認トップ画面から、月次収支確認画面や年間収支確認画面(グラフ描画)などが確認できれば成功です。

最後に
以上、RubyonRailsを使ってシンプルな家計簿アプリを作成してみました。
これにスタイルシートなどを作成してレイアウトを整えたり、細かい微調整を対応していけばざっくりした家計簿アプリが完成すると思います。
※一応、ここまで作成した家計簿アプリのソースを以下からダウンロードできます。
RubyOnRailsでのアプリ作成の参考になれば幸いです。
それでは!!

