Rails Tutorial 未読のMicropostに青丸をつける (Ruby on Rails Tutorial 第四版)

# Home（マイページ）のFeedに未読情報を追加したい
[Rails Tutorial](https://railstutorial.jp/chapters/beginning?version=5.0#sec-installing_rails)で作成したTwitter機能に，未読の情報を自分のFeed (タイムライン)に表示できるようにしてみた．
# 方針
各Micropostにnew flagというカラムを追加することを一瞬考えたが，それだとあるユーザーが既読にしてしまうと他のユーザーにとってもそのMicropostが既読になってしまうのでだめ．
そのため方針としては，ユーザーがHomeに最後にアクセスした時間(lastaccesshome)をカラムに追加し，Micropostが更新された時間(updated_at)と比較して未読・既読を判断することにした．
# やってみる
まず，usersにHomeに最後にアクセスした時間をlastaccesshomeとしてカラムに追加．
型はupdated_atと同じdatetime型にしておく．

```
rails generate migration AddLastaccesshomeToUsers lastaccesshome:datetime
```

できたファイルにdefault値も追加しておく．ここではDatetime.nowを追加した．

```ruby:db/migration/[timestamp]_add_lastaccesshome_to_users.rb
class AddLastaccesshomeToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :lastaccesshome, :datetime, default:DateTime.now
  end
end
```

# 問題点
このあと，実際に値を比較して未読・既読の判定を行うのだが，Rails TutorialではMicropostのFeedを表示するviewは一つにしている，つまりHomeで表示されるFeedとprofileで表示されるFeedは同じviewにrenderしている．
今回，未読情報の表示はHomeで表示されるFeedのみにしたい（と僕は思った）ので，区別して表示される必要がある．

もう一つ，未読を既読にする処理（lastaccesshomeを更新する処理）を行うメソッドをstatic_pages_controller.rbで定義するのだが，after_actionとして実行するとエラーが出てきてしまうという問題も起きた．
#解決策
上記の二つの問題を一気に解決する手軽な手段として，ユーザにカラムをもう一つ追加するという手段を考えた（あまり良くない手段かもしれない）．
具体的にはアクセスしたその瞬間の時間を持つものとしてaccesstimeというカラムを追加する．

```
rails generate migration AddAccesstimeToUsers accesstime:datetime
```

```ruby:db/migration/[timestamp]_add_accesstime_to_users.rb
class AddAccesstimeToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :accesstime, :datetime, default:DateTime.now
  end
end
```

これによって，
一つ目の問題に対しては，usersのcontrollerにはbefore_actionとして既読処理メソッドを初めの計画通り追加することで先にlastaccesshomeを更新して，必ず既読になるようにした．
二つ目の問題に対しては，static_pagesのcontrollerにbefore_actionとして既読処理メソッドを追加するが，accesstimeの値をlastaccesshomeに代入したあと，accesstimeの値を現在の値に更新することでbefore_actionによって最終ログインの時間が先に更新されて消えてしまうことを防ぐようにした．

# コード
実際変更した部分は以下．
## controller
```ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
    .
    .
    .
  before_action :read, only: :show
    .
    .
    .
    #before action
 　　　　　　.
    .
    .
　#既読処理メソッド
    def read
      @user = current_user
      @user.lastaccesshome = Time.zone.now
      @user.save!
    end
end
```

```ruby:app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
  before_action:read, only: :home
    .
    .
    .
  private
  #before_action
　　　　#既読処理メソッド
   def read
    if logged_in?
      @user = current_user
      @user.lastaccesshome = @user.accesstime
      @user.accesstime = DateTime.now
      @user.save!
    end
  end
end
```

## view
未読情報を示す青丸のscss(適当に作りました)

```scss:custom.scss
/* microposts */

.microposts {
 .
 .
 .
  .newsign {
    float: right;
    border-radius: 50%;
    height: 20px;
    width: 20px;
    // background-color: rgb(63, 59, 247);
    background: skyblue;
  }
 .
 .
 .
}
```
次に，各micropostについてcurrent userのlastaccesshomeとmicropostのupdated_atを比較し，updated_at > lastaccesshomeの場合にのみ青丸を表示するように，app/views/micropostsにある_micropost.html.erbを変更．

```html:app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
  <%= micropost.content %>
  <% if micropost.created_at > current_user.lastaccesshome %>
  <span class="newsign"></span>
  <% end %>
  <%= image_tag micropost.picture.url if micropost.picture? %>
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
    <% if current_user?(micropost.user) %>
      <%= link_to "delete", micropost, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>
  </span>
</li>
```

# 実行結果
実際に作ったものは[こちら](https://floating-brook-74205.herokuapp.com/)．
以上の変更を加えた後，herokuにデプロイして動くことを確認．
試しに新しくユーザ(hoge)を作成し，example userでそのユーザをフォローした後hogeで何かを投稿し，それがexample userのHomeで新情報として青丸がついているか確かめてみる．
example userでhogeをフォローした後，hogeのhomeで「hoge」と投稿．新しく投稿した情報として青丸で表示される．
<img width="1279" alt="スクリーンショット 2018-07-13 13.26.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/264208/8bfdda8f-4d90-b5cb-3751-612538e16340.png">
リロードすると青丸は消える．
次にexample userでログインし，Homeにアクセスする．<img width="1280" alt="スクリーンショット 2018-07-13 13.27.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/264208/684d5242-771c-dc0a-b286-c7cd2f8a3e00.png">
example userの前回アクセスの後に投稿されたhogeの「hoge」が新規情報として表示されている．
リロードすると青丸は消える．望んでいた処理ができた．
<img width="1280" alt="スクリーンショット 2018-07-13 13.27.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/264208/482f8620-c115-4a0b-b083-72dcb710c1b0.png">
なお，他のユーザのプロフィールにおいては青丸はついていないことも確認できる．
<img width="1279" alt="スクリーンショット 2018-07-13 13.27.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/264208/bd664951-54ab-c581-35eb-946d4f7e5ff4.png">

#　最後に
今回実装した方法よりもっといい方法がありそう．カラムを二つも追加するのはかなり冗長な気がする．
ぜひあれば教えてください．