【Rails】impressionistを用いてPV数ランキングの実装

# 目標

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/bfadc8da-20f1-aff1-473d-9246594ec38f.gif)

# 開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記実装済み。

・[Slim導入](https://qiita.com/matsubishi5/items/b639ffddecc626856039)
・[ログイン機能実装](https://qiita.com/matsubishi5/items/5bd8fdd45af955cf137d)

# 実装

### 1.`impressionist`を導入

**※バージョンを指定する事に注意！(指定しないとエラーが出た)**

```ruby:Gemfile
gem 'impressionist', '~>1.6.1'
```

```terminal:ターミナル
$ bundle
```

```terminal:ターミナル
$ rails g impressionist
```

```terminal:ターミナル
$ rails db:migrate
```

```ruby:schema.rb
create_table "impressions", force: :cascade do |t|
  t.string "impressionable_type"
  t.integer "impressionable_id"
  t.integer "user_id"
  t.string "controller_name"
  t.string "action_name"
  t.string "view_name"
  t.string "request_hash"
  t.string "ip_address"
  t.string "session_hash"
  t.text "message"
  t.text "referrer"
  t.text "params"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.index ["controller_name", "action_name", "ip_address"], name: "controlleraction_ip_index"
  t.index ["controller_name", "action_name", "request_hash"], name: "controlleraction_request_index"
  t.index ["controller_name", "action_name", "session_hash"], name: "controlleraction_session_index"
  t.index ["impressionable_type", "impressionable_id", "ip_address"], name: "poly_ip_index"
  t.index ["impressionable_type", "impressionable_id", "params"], name: "poly_params_request_index"
  t.index ["impressionable_type", "impressionable_id", "request_hash"], name: "poly_request_index"
  t.index ["impressionable_type", "impressionable_id", "session_hash"], name: "poly_session_index"
  t.index ["impressionable_type", "message", "impressionable_id"], name: "impressionable_type_message_index"
  t.index ["user_id"], name: "index_impressions_on_user_id"
end
```

### 2.カラムを追加

```terminal:ターミナル
$ rails g migration AddImpressionsCountToUsers impressions_count:integer
```

```ruby:~_add_impressions_count_to_users.rb
class AddImpressionsCountToUsers < ActiveRecord::Migration[5.2]
  def change
    # 「default: 0」を追記
    add_column :users, :impressions_count, :integer, default: 0
  end
end
```

```terminal:ターミナル
$ rails db:migrate
```

### 3.モデルを編集

```ruby:user.rb
# 追記
is_impressionable counter_cache: true
```

`is_impressionable`
➡︎ Userモデルで`impressionist`を使用出来る様にする。

**※`counter_cache: true`を必ず付与して下さい。**

### 4.コントローラーを編集

```ruby:users_controller.rb
def index
  @users = User.order(impressions_count: 'DESC') # ソート機能を追加
end

def show
  @user = User.find(params[:id])
  impressionist(@user, nil, unique: [:session_hash]) # 追記
end
```

`User.order(impressions_count: 'DESC')`
➡︎ ユーザー一覧をPV数の多い順に並び替える。

`impressionist(@user, nil, unique: [:session_hash])`
➡︎ ユーザー詳細ページにアクセスするとPV数が1つ増える。

【IPアドレスで計測する場合】
`impressionist(@tourist_spot, nil, unique: [:impressionable_id, :ip_address])`

**※自主的にPV数を伸ばす事が出来ない様に、1ユーザーにつきPV数をカウントするのは1回まで。**

### 5.ビューを編集

```slim:users/index.html.slim
table.table
  thead
    tr
      th
        | 順位
      th
        | 氏名
      th
        | PV数

  tbody
    - @users.each.with_index(1) do |user, index|
      tr
        td
          = index
          | 位
        td
          = link_to user do
            = user.name
        td
          / PV数を表示
          = user.impressions_count
```