ratyrateを使用したRailsの星型評価を実装する

Railsで星の評価機能を実装する方法です。

# 環境

Rails 5.2.3
mysql
gem ratyrate
gem devise

# Goals
以下のように星の評価を実装したアプリの作成
GitHub:[testGemRatyrate](https://github.com/NMurata07/testGemRatyrate)

![FireShot Capture 116 - TestGetRatyrate - http___localhost_3000_cars_1.png](https://qiita-image-store.s3.amazonaws.com/0/288694/4fb8bd07-9ede-7579-83f6-7e6e727ec179.png)


# 背景

Railsで星の評価機能を実装しようとした際、`jquery.raty`を使用する方法は参考記事が沢山あるのですが、jqueryの知識を要求されたり、画像をダウンロードしたりと手間がかかります。

もっと手軽に実現できないか調べたところ、`ratyrate`というgemがあることを知りました。
しかし、Rails5.2.3では公式の方法ではエラーで使用することができませんでした。

そこで、Rails5.2.3で使用する方法をまとめました。

# 準備

## ratyrateのインストール

`ratyrate`はjqueryを使用しているので、`jquery-rails`も一緒にインストールします。
また、`devise`と連携させるので`devise`も加えます。
Gemfileに以下をグローバルに記入します。

```
gem 'devise'
gem 'jquery-rails'
gem 'ratyrate'
```

インストールをします。

```
bundle install
```

## 評価者の設定

devise:userとratyrateを作成します。

```
rails g devise:install
rails g devise user
# 以下を実行すると、星画像やmigrationファイル等が作成される
rails g ratyrate user
```
## Migration

生成されるmirationファイルは、以下の４つになります。
- `db/migrate/20140814135421_create_rating_caches.rb`
- `db/migrate/20140706144643_create_rates.rb`
- `db/migrate/20140814135422_create_average_caches.rb`
- `db/migrate/20140814135423_create_overall_averages.rb`

この状態でmigrationを実行するとエラーになり、migrationに失敗してしまいます。
そこで、各ファイルを以下のように編集します。

### create_rating_caches.rb

```ruby
class CreateRatingCaches < ActiveRecord::Migration[5.2]

  def self.up
      create_table :rating_caches do |t|
        t.belongs_to :cacheable, :polymorphic => true
        t.float :avg, :null => false
        t.integer :qty, :null => false
        t.string :dimension
        t.timestamps
      end
    end

    def self.down
      drop_table :rating_caches
    end

end
```

### create_rates.rb

```ruby
class CreateRates < ActiveRecord::Migration[5.2]

    def self.change
      create_table :rates do |t|
        t.belongs_to :rater
        t.belongs_to :rateable, :polymorphic => true
        t.float :stars, :null => false
        t.string :dimension
        t.timestamps
      end
    end

    def self.down
      drop_table :rates
    end

end
```

### create_average_caches.rb

```ruby
class CreateAverageCaches < ActiveRecord::Migration[5.2]

  def self.up
    create_table :average_caches do |t|
      t.belongs_to :rater
      t.belongs_to :rateable, :polymorphic => true
      t.float :avg, :null => false
      t.timestamps
    end
  end

  def self.down
    drop_table :average_caches
  end

end
```

### create_overall_averages.rb

```ruby
class CreateOverallAverages < ActiveRecord::Migration[5.2]

  def self.up
    create_table :overall_averages do |t|
      t.belongs_to :rateable, :polymorphic => true
      t.float :overall_avg, :null => false
      t.timestamps
    end
  end

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

編集したらmigrationを実施します。

```
rails db:migrate
```

## javascriptの読み込み

`app/assets/javascripts/application.js`に以下を追記します。
この時、`//= require rails-ujs`より上に記述します。

```js
//= require jquery
//= require jquery.raty
//= require ratyrate
```

以上で、ratyrateを使用する準備が整いました。

# アプリ作成

実際にratyrateを実装したアプリを作成します。
作成するアプリは車のスピードを評価するものです。

## 準備

scaffoldを使用してモデルを作成

```
rails g scaffold car name:string
```

migrationを実施します。

```
rails db:migrate
```

## コードの編集

メインとなる箇所を抜粋します。

### Model

#### car.rb

```ruby
class Car < ApplicationRecord
  ratyrate_rateable "speed" # 追加
end
```

補足:
`ratyrate_rateable`で評価対象となる項目を指定します。
複数ある場合は、カンマ区切りになります。

例:

```ruby
ratyrate_rateable "speed", "engine", "price"
```

#### user.rb

```ruby
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  ratyrate_rater # 追加
end
```

### View

#### app/views/cars/show.html.erb

星を表示したい場所へ以下を記述します。

```erb
<p>Speed : <%= rating_for @car, 'speed' %></p>
```

以上で完成です。

# その他オプション

## 再評価

デフォルトの設定では、一旦評価すると変更できません。
そこで以下のオプションを付けることで、評価を変更できるようになります。

```erb
<%= rating_for @car, 'speed', disable_after_rate: false %>
```

![FireShot Capture 117 - TestGetRatyrate - http___localhost_3000_cars_1.png](https://qiita-image-store.s3.amazonaws.com/0/288694/a0c568af-466e-5e03-fb1d-28a09bac2b92.png)

## 星の数の変更

```erb
<%= rating_for @car, 'speed', star: 10 %>
```

![FireShot Capture 118 - TestGetRatyrate - http___localhost_3000_cars_1.png](https://qiita-image-store.s3.amazonaws.com/0/288694/10e59c9a-3a0c-3fa0-7b91-e8e35973f9b5.png)

## 星半分

```erb
<%= rating_for @car, 'speed', disable_after_rate: false, enable_half: true %>
```

![FireShot Capture 119 - TestGetRatyrate - http___localhost_3000_cars_1.png](https://qiita-image-store.s3.amazonaws.com/0/288694/c26e9397-bfa9-c0ac-241a-b4566f04f1e9.png)

## 平均値の表示

```erb
<%= rating_for car, 'speed', disable_after_rate: true, imdb_avg: true %>
```

![FireShot Capture 120 - TestGetRatyrate - http___localhost_3000_cars.png](https://qiita-image-store.s3.amazonaws.com/0/288694/68c5f68d-cfcf-94a3-67c4-8e8b575cb9fc.png)


その他にもオプションが用意されているので、[wazery/ratyrate](https://github.com/wazery/ratyrate)や[Ratyrate: Add Rating to Your Rails App](https://www.sitepoint.com/ratyrate-add-rating-rails-app/)で確認してください。

# 最後に

ratyrateを使用することで、評価用のテーブルは不要になり、実装もシンプルでスマートになりました。

#### 参考
- [wazery/ratyrate](https://github.com/wazery/ratyrate)
- [Ratyrate: Add Rating to Your Rails App](https://www.sitepoint.com/ratyrate-add-rating-rails-app/)