Ruby on Railsを触ってみる ⑨月別アーカイブ
なんとなくWebアプリっぽくなってきたTwiceだが、Twitterが公式で提供しているアーカイブのダウンロードでは、JSで動作する過去のツイートを参照できる機能が付いている。月別アーカイブと検索機能が付いているため、せめてそれぐらいは実装しないと、ここまで作った甲斐がないというものではないか。
というわけで、月別アーカイブ機能的なものを作りたい。 サイドバーあたりに、投稿があった年月+件数を表示し、選択するとその年月のツイートを参照できる、といった具合にしたい。 コントローラにアーカイブを集計するメソッドを作る。 年月でGroup by するために、timestampをyyyymmに変換し、groupで指定する。
class TweetsController < ApplicationController before_action :set_tweet, only: [:show, :edit, :update, :destroy] before_action :check_user before_action :make_archive # ユーザがログインしていなければ、ホームにリダイレクト def make_archive @user = current_user @archives = @user.tweet.group("strftime('%Y%m', tweets.timestamp)") .order("strftime('%Y%m', tweets.timestamp) desc") .count end
Tweetページの時のみサイドバーに表示したいので、view/layouts/tweets.html.erbを作成する。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><%= content_for?(:title) ? yield(:title) : "Twice" %></title> <%= csrf_meta_tags %> <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> <!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.1/html5shiv.js" type="text/javascript"></script> <![endif]--> <%= stylesheet_link_tag "application", :media => "all" %> <!-- For third-generation iPad with high-resolution Retina display: --> <!-- Size should be 144 x 144 pixels --> <%= favicon_link_tag 'apple-touch-icon-144x144-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '144x144' %> <!-- For iPhone with high-resolution Retina display: --> <!-- Size should be 114 x 114 pixels --> <%= favicon_link_tag 'apple-touch-icon-114x114-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '114x114' %> <!-- For first- and second-generation iPad: --> <!-- Size should be 72 x 72 pixels --> <%= favicon_link_tag 'apple-touch-icon-72x72-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '72x72' %> <!-- For non-Retina iPhone, iPod Touch, and Android 2.1+ devices: --> <!-- Size should be 57 x 57 pixels --> <%= favicon_link_tag 'apple-touch-icon-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png' %> <!-- For all other devices --> <!-- Size should be 32 x 32 pixels --> <%= favicon_link_tag 'favicon.ico', :rel => 'shortcut icon' %> <%= javascript_include_tag "application" %> </head> <body> <div class="navbar navbar-fluid-top"> <div class="navbar-inner"> <div class="container-fluid"> <a class="btn btn-navbar" data-target=".nav-collapse" data-toggle="collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> <a class="brand" href="#">Twice</a> <div class="container-fluid nav-collapse"> <ul class="nav"> <li><%= link_to "Link1", "/path1" %></li> <li><%= link_to "Link2", "/path2" %></li> <li><%= link_to "Link3", "/path3" %></li> <% if user_signed_in? %> <li><%= link_to "ログアウト", (destroy_user_session_path) %></li> <% else %> <li><%= link_to "ログイン", (user_omniauth_authorize_path :twitter) %></li> <% end %> </ul> </div><!--/.nav-collapse --> </div> </div> </div> <div class="container-fluid"> <div class="row-fluid"> <div class="span3"> <div class="well sidebar-nav"> <ul class="nav nav-list"> <li class="nav-header">Archives</li> <% @archives.each do |yyyymm, count| %> <li><%= ymconv(yyyymm, count.to_s) %><li> <% end %> </ul> </div><!--/.well --> </div><!--/span--> <div class="span9"> <%= bootstrap_flash %> <%= yield %> </div> </div><!--/row--> <footer> <p>© Company 2014</p> </footer> </div> <!-- /container --> </body> </html>
年月件数表示にはヘルパーメソッドを作成した。 コントローラではyyyyMMと件数という形式で集計結果が出される。'yyyy年MM月'とも出せたのだが、アーカイブ表示画面の遷移に使えなくなりそうなので、単純な形式にした。そこでtweet_helper.rbにymconvというヘルパーメソッドを作り'yyyy年MM月(件数)'という形式の文字列で出力させることでViewをスッキリさせる。
# coding: utf-8 module TweetsHelper def ymconv(yyyymm,cnt) yyyy = yyyymm[0,4] mm = yyyymm[4,2] return yyyy + "年" + mm + "月 (" + cnt + ")" end end
ここからリンクをクリックしたら、その年月のツイートが表示されるようにしたい。 コントローラにメソッドを追加する。 年月のパラメータを受け取って、ツイートを絞り込む。
# GET /tweets/archives?yyyymm=201402 def archives @user = current_user @yyyymm_now = params[:yyyymm] @tweets = @user.tweet .where("strftime('%Y%m', tweets.timestamp) = '"+@yyyymm_now+"'") .order(:id) .page params[:page] end
ルーティングも修正する。archivesへのルートを追加。
resources :tweets do collection do get 'import_csv_new' post 'import_csv' get 'archives' end end
「yyyy年MM月のツイート」と表示したいので、もう一つhelperメソッドを作る。
def ymconvn(yyyymm) yyyy = yyyymm[0,4] mm = yyyymm[4,2] return yyyy + "年" + mm + "月 " end
これを使ってViewファイル、archives.html.erbを作成する。
<h1><%= ymconvn(@yyyymm_now) %>のツイート一覧</h1> <%= render(@tweets) %> <% if @tweets.count == 0 %> <p><%= ymconvn(@yyyymm_now) %> のツイートはありません</p> <% end %> <%= paginate (@tweets) %>