【Rails】自分のアクティビティ一覧を表示する【通知機能の応用】

こんにちは！
ねこじょーかー（[@nekojoker1234](https://twitter.com/nekojoker1234)）と申します。

先日、ゼロから独学で勉強して、Webサービス「[Lookmine](https://lookmine.herokuapp.com/)」を立ち上げました。

このサービスでは、以下のような通知機能を実装しています。

<img width="330" alt="通知一覧" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487218/ae12a7ca-165b-f026-da28-99a91f9575d8.png">

この機能を応用して、自分が「いいね、コメント、フォロー」した履歴を「アクティビティ」として一覧で見る機能を作りました。

<img width="330" alt="アクティビティ一覧" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487218/761f5eb3-959a-a217-bacf-a0b71f98b38c.png">

やっぱり、誰にいいねをしたとか、誰に何のコメントをしたとかは一覧で見れたほうがいいですよね。

そんなわけで、実装方法をこの記事で解説することにしました。

通知機能の実装が終わっている前提なので、まだ通知機能が出来ていない人は、「[通知機能を実装する方法](https://qiita.com/nekojoker/items/80448944ec9aaae48d0a)」から読んでくださいね。

## アクティビティ一覧画面の作成

アクティビティ一覧の画面を作っていきましょう。
まずは、アクティビティコントローラーの作成からです。

```
$ rails g controller activities
```

通知一覧の画面は`index`で作るので、ルーティングを追加しておきましょう。
他のメソッドは不要なので、`only`を追加しています。

```ruby:config/routes.rb
  resources :activities, only: :index
```


`index`アクションを実装します。

```ruby:app/controllers/activities_controller.rb
class NotificationsController < ApplicationController
  def index
    @activities = current_user.active_notifications.page(params[:page]).per(20)
  end
end
```

アクティビティの一覧を表示するために新しくテーブルを作る必要はなく、通知機能で使ったテーブルをそのまま流用します。

今回は、`active_notifications`で、自分が送った通知を取得します。

通知機能の実装で、以下の記述をしたのを覚えていますか？

```ruby:app/models/user.rb
  has_many :active_notifications, class_name: 'Notification', foreign_key: 'visitor_id', dependent: :destroy
  has_many :passive_notifications, class_name: 'Notification', foreign_key: 'visited_id', dependent: :destroy
```

通知機能のときは、`passive_notifications`を使って、相手に送った通知を取得していました。
今回は自分が送った通知を取得したいので、`active_notifications`を使います。

次に、画面の実装です。
`index`の画面を作っていきましょう。

```slim:app/views/activities/index.html.slim
.col-md-6.mx-auto
  - if @activities.exists?
    - @activities.each do |activity|
      = render 'activities/activity', activity: activity
  - else
    p.text-center
      | アクティビティはありません
```

自分が送った通知の分だけ、部分テンプレート`_activity.html.slim`を呼び出しています。


```slim:app/views/activities/_activities.html.slim
- visitor = activity.visitor
- visited = activity.visited
.form-inline
  span      
    - case activity.action
    - when 'follow' then
      = link_to user_path(visited) do
        = image_tag avatar_url(visited).to_s, class: "icon_mini" 
        strong
          = visited.name
      = "さんをフォローしました"
    - when 'like' then
      span
        = link_to post_path(activity.post) do
          = image_tag avatar_url(activity.post.user).to_s, class: "icon_mini" 
          strong
            = activity.post.user.name + 'さんの投稿'
      = "にいいねしました"
    - when 'comment' then
      - if activity.post.user_id == visitor.id
        = link_to "あなたの投稿", activity.post, style: "font-weight: bold;"
      - else
        span
          = link_to post_path(activity.post) do
            = image_tag avatar_url(activity.post.user).to_s, class: "icon_mini" 
            strong
              = activity.post.user.name + 'さんの投稿'
      = "にコメントしました"
      p.text-muted.mb-0
        = Comment.find_by(id: activity.comment_id)&.comment

.small.text-muted.text-right
  = time_ago_in_words(activity.created_at).upcase
hr
```

これを実装すると、以下のアクティビティ一覧が出来上がります。

<img width="330" alt="アクティビティ一覧" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487218/761f5eb3-959a-a217-bacf-a0b71f98b38c.png">

フォローは相手のプロフィールをリンクにしています。

コメントは、コメント先の投稿をリンクにしていて、自分の投稿に対するコメントは「あなたの投稿」という表現にしています。
自分の投稿なのに「〇〇さんの投稿にコメントしました」という表現は、違和感がありますよね。

これで完成です！
お疲れさまでした！

##あわせて読みたい

- [HTMLもわからない初心者が、独学で「投稿型SNSサービス」を作ったって本当？【193日間の死闘】](https://qiita.com/nekojoker/items/2497b4f81ffd1cd7025c)
- [Webプログラミング「経験０」の私が、「193日間の独学」でWebサービスを立ち上げた話](https://note.mu/nekojoker/n/nabe32d6d961f)（外部リンク）

運営している PlayFab 専用ブログ
https://playfab-master.com