読者です 読者をやめる 読者になる 読者になる

Ruby + Heroku + Highchartsで食べたリンゴを月別にグラフ化してみた

Heroku Padrino Ruby

以前、リンゴ全体の食べた割合をグラフ化してみました。
Ruby + Heroku + Highchartsで食べたリンゴの割合をグラフ化してみた - メモ的な思考的な


ただ、これではどの時期に何のリンゴを食べたのか、つまり旬のリンゴは何なのかが分かりづらい状態でした。
そのため、今回は月別のグラフを追加してみることにしました*1

■2013/3/31時点

シナノゴールドばかり食べていたせいで、旬のリンゴがよく分かりません...
8月あたりからツガルが始まり、9月と10月頃はトキや秋映を食べていたような気がします。

■悩んだことと対応

HighChartsのうち、どのグラフを使うか

HighChartsにはデモサイトがあり、使えるグラフの一覧があります。今回は「Stacked area」を選びました。
Highcharts - Basic line


HighChartsにおいて、前回利用した「pie」との作り方の違いとしては、以下のようなものでした。

  • pie: 一つのseriesを使い、addPointsで割合を加える
  • area: 複数のseriesを使い、addSeriesで割合を加える

参考:HighCharts load data via ajax - Stack Overflow



メニューなどの表現

TwitterBootstrapのCDNがあれば使ってみるかと調べてみたところ、以下のものがありました。
Bootstrap CDN


「...Don't believe us? Ask these guys: 」と書いてありましたのでたぶん大丈夫だろうと思い、今回は試してみることにしました。



haml中の日本語表記について

何もせずに日本語を記載したところ、エラーで動作しなくなりました。
以下のサイトを参考に、config/boot.rbのPadrino.before_loadに処理を追加しました。
参考:http://blog.cabbagekobe.info/blog/2012/11/06/padorino-haml-japanese/


config/boot.rb

Padrino.before_load do
  Encoding.default_internal = nil
  Encoding.default_external = 'UTF-8'
end
hamlに値を渡すには

haml側からはコントローラーのインスタンス変数が参照できたので、それを利用しました。
ただ、使うjavascriptを切り替えるために、インスタンス変数へパスを設定したのは良かったのかどうか...

controllers/apples.rb

get :index, map: "/" do
  @highchart_path = "/javascripts/total.js"
  @home_active = "active"
  render "apples/index"
 end


application.haml

%script{ src: @highchart_path, type: "text/javascript"}


参考:http://www.sinatrarb.com/intro-jp.html#%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E5%86%85%E3%81%A7%E5%A4%89%E6%95%B0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B



ページ共通のテンプレート使用

今回はページが2つに増えたことから、ページ共通のテンプレートを app/views/layouts/application.haml として作成しました。
一方個別のページは、 app/views/apples/ 配下に作りましたが、実際のところは両方とも同じです。



食べたリンゴの個数を月別に集約するには

前回ローカルのDBをPostgreSQLにしたおかげで、ローカルでもPostgreSQLの独自関数が使えるようになりました。
そのため、Modelのscopeで以下の集計を行いました。

scope :count_apple_monthly,
  select("name, to_char(tweeted_at, 'MM') as month, count(name) as amount")
  .group('name, month')
  .order('name, month')

参考:http://www.postgresql.jp/document/9.1/html/functions-formatting.html



戻り値だけで使うクラスを用意するには

RubyのStructクラスを使いました。
参考:class Struct


そもそも必要になった経緯はというと、上記のSQL

name month amount
シナノゴールド 01 20
シナノゴールド 02 5
フジ 01 10

のように取得できるのですが、HighChartsのSeriesで扱うには、amountを[20,5,..]のような配列で持たせる必要がありました。


このように縦持ちを横持ちに変換するのを、SQLRubyJavaScriptのどこでやろうかと考えましたが、せっかくだからRubyを使うことにしました。
そこでPadrinoのhelperの中でやることにしたところ、メソッドの戻り値で使えるクラスを定義する必要が出てきました。


その戻り値用のクラスをどこかで定義しようと考えたのですが、Padrinoでは定義したものをどこに置けばよいか分かりませんでした。
そこでいろいろと調べてみたところ、Structクラスを知ったため、使うようにしました。
参考:

■負債の返済

前回の「良くない設計」であげていた、

  • モデルへ入れる際のSELECTで、ダミーの列を取得
  • JSONで渡す際に、app/helpers/apples_helper.rb のadd_colorメソッドで、モデルのダミー項目を上書き

について、Structクラスを使えばダミー列とかを使わなくて済むことが分かりました。
そのため、今回のタイミングで、そちらの部分もStructを使うように修正しました。

*1:最初は年別月別の集計も考えましたが、そもそも旬のリンゴを知りたかったため、年はあまり関係ないだろうと考えました。よって、年は考慮せずに月別に集計することにしています。