【rails】PV数の実装(impressionist)

#実装すること

* gem impressionistを使用して、投稿ページにPV(ページビュー)を設置します。
* 同じユーザーがPV数を稼ぐ、増やせないように同じセッションはカウントしないようにします。

impressionist: https://github.com/charlotte-ruby/impressionist
こちらのgithubを参考に実装していきます。

#完成形

目のアイコンがPV数を表示しており、
投稿詳細に行くと数字がカウントされています。

![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1029483/7c0ab185-bf7e-8084-f241-f75dcacf1ca9.gif)

#前提
下記の機能実装済み。
・devise(今回は、memberモデル)
・投稿機能(今回は、questionモデル)

```ruby:schema.rb
ActiveRecord::Schema.define(version: 2021_05_05_122222) do

  create_table "members", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.datetime "remember_created_at"
    t.string "name", default: "", null: false
    t.text "introduction"
    t.string "image_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["email"], name: "index_members_on_email", unique: true"index_members_on_reset_password_token", unique: true
  end

  create_table "questions", force: :cascade do |t|
    t.integer "member_id", null: false
    t.string "title", default: "", null: false
    t.text "content", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["member_id"], name: "index_questions_on_member_id"
  end
end
```

#手順
①gem"impressionist"の導入
②modelへの記載
③controllerへの記載
④viewへの記載

#実装


###1. impressionistのインストール

railsのバージョンに注意。(6と5以下で異なる)
私は5なので、下記を記載。

```ruby:Gemfile
#rails 5 or lower
gem 'impressionist', '~>1.6.1'
```
インストールします。

```ruby:terminal
bundle install
```
impressionistのマイグレーションファイルを作成します。

```ruby:terminal
rails g impressionist
```
下記が自動的に作成されます。
*user_idとありますが、ここは特にいじる必要はありません。
　私はuserではなく、memberを使用していたのでmember_idに修正したところエラーが出ました。　
　私自身が作成したmemberモデルを表すidではなかったです。


```ruby:create_impressions_table.rb
class CreateImpressionsTable < ActiveRecord::Migration[5.2]
  def self.up
    create_table :impressions, :force => true 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.timestamps
    end
    add_index :impressions, [:impressionable_type, :message, :impressionable_id], :name => "impressionable_type_message_index", :unique => false, :length => {:message => 255 }
    add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false
    add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false
    add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false, :length => {:params => 255 }
    add_index :impressions, :user_id
  end

  def self.down
    drop_table :impressions
  end
end
```

dbに反映させましょう。

```ruby:terminal
rails db:migrate
```
###2. modelへの記載

```ruby:models/question.rb
class Question < ApplicationRecord
  is_impressionable

  belongs_to :member

  validates :title, presence: true
  validates :title, length: { minimum: 5, maximum: 50 }, allow_blank: true
  validates :content, presence: true
  validates :content, length: { minimum: 20 }, allow_blank: true

end
```
下記を一番上に追加しています。

```
is_impressionable

or

is_impressionable :counter_cache => true
```

これを追加することで、questionモデルでimpresionistを使う事ができます。


###3. controllerへの記載

```ruby:questions_controller.rb
class Public::QuestionsController < ApplicationController
  impressionist :actions => [:show]

  def show
    @member = current_member
    @question = Question.find(params[:id])
    impressionist(@question, nil, unique: [:session_hash.to_s])
  end
```

それぞれ説明します。


```ruby:①
impressionist :actions => [:show]
```

⇨ PV数を計測したいので、アクションを指定します。

  　・投稿詳細(questions#show)で計測したい。
  　・[   ]内は、計測したいアクションを記載。


```ruby:②
impressionist(@question, nil, unique: [:session_hash.to_s])
```

⇨ showアクション内にも記載します。

  　・@questionを計測する対象として設定します。
    　　今回は、投稿詳細なので@question。showにある変数を入れましょう。

  　・uniqueでは、どの値で計測するかを書きましょう。今回は、sessionで計測したいので、
    　　先ほど作成した、マイグレーションファイルのカラム名を書きましょう。(参照： t.string :session_hash)



###4.viewへの記載
＊わかりやすくするために余計な箇所は省いてあります。

```erb:questions/show.html.erb
<div class="container">
 <div class= "row">
   <div class="col-md-3 pt-5">
　　　<i class="fas fa-eye"> 
　　　　<%= @question.impressionist_count(:filter=>:session_hash) %>　
　　　</i>
   </div>
 </div>
</div>
```

ここで計測(いわゆるcount)したいので、下記を記載します。

```erb:
<%= @question.impressionist_count(:filter=>:session_hash) %>
```

・ impressionist_countで計測。
・ (:filter=>:session_hash)でフィルターをかけ、どれで計測するか設定。
　 今回は、sessionで計測なので、記載の通り。

これで問題なく計測できるかと思います。
もし、エラーや上手く動かない。などあればコメント頂けたらと思います。

<br>
以上です。