ratyを用いた星評価機能の実装( ruby on rails )

# まえがき
**[DMM WEBCAMP Advent Calendar 2023](https://qiita.com/advent-calendar/2023/infratop)** 12日目記事です。

DWCメンター・卒業生が記事を投稿しておりますので、是非他の記事もご確認ください！
# 初めに
ここでは，rubyのフレームワークであるruby on railsで，星評価機能をratyを用いて実装する手順について説明します。

# 1. githubからファイルをダウンロード & 解凍
[こちらのgithubリポジトリ](https://github.com/wbotelhos/raty)に移動し，緑色の`Code`ボタンをクリック。
`Download ZIP`があるため，そちらをクリックし，リポジトリのファイル群をダウンロードする．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1967037/8932cc84-36db-fe61-6a74-101606a7f81a.png)
ダウンロード後，
Macの場合は該当ダウンロードディレクトリをダブルクリックすると自動的に解凍されます。
Windowsの場合は，該当ダウンロードフォルダを右クリックし，すべて展開をクリックすると、展開できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1967037/a8fbaffd-1f6e-1a76-a119-5fcb1033fb78.png)

# 2. imageファイルをassets/images
展開したファイルの中の，`src/images`の中に入っている5つの画像ファイルを，すべて開発しているアプリのディレクトリ`app/assets/images`の中にコピーする．
コピーする画像の一覧は以下のとおりとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1967037/0265206f-b521-c98a-4813-eb3091926229.png)

# 3. jsファイルをコピー & 読み込み設定
解凍したディレクトリの中にある`src/raty.js`ファイルを`app/javascript/packs`下にコピーする．

次に，`app/javascript/packs/application.js`に下記のコードを追記する．
```javascript:packs/application.js
import Raty from "./raty.js"         // 同じ階層にあるraty.jsをRatyという名前でインポート

// ratyアクションの定義
window.raty = function(elem,opt){ 
    var raty =  new Raty(elem,opt)
    raty.init();
    return raty;
}
```
### windowオブジェクト
- 画面上に表示されているすべてのオブジェクトの親となるオブジェクト
- Javascriptのオブジェクトの最上位に位置する
- ウィンドウに関する情報の取得や、ウィンドウを設定・操作する

つまり、これを設定することによって、viewのscriptタグ内で、ratyという関数が実行可能になる。
raty関数実行時には、function(elem, opt)が実行されるため、raty関数には2引数のelem, optの設定が必要である。

### functionとは
- 様々な処理を1つにまとめて、名前を付けることができる
- 単調な処理を1つにまとめて、どこからでも使えるように効率化する目的で使われる

今回は、`elem`, `opt`の2引数を使用して、**Ratyクラス**が新規作成され、新規作成された`init()`が実行され、その結果が表示されます。

:::note warn
注意
上記の設定は，app/views/layouts/application.html.erbの中で，
javascript_pack_tag 'application' の設定をしている場合となります。
他のファイルを読み込んだり，直接ファイルパスを指定する場合はこの設定に限らない．
:::

# 投稿フォームに星レビュー機能を追加
## 1. starカラムをbookに追加
`rails g migration AddStarToBooks star:integer`
starをinteger型で追加するマイグレーションファイルを作成．
`rails db:migrate`を実行し，DBに反映させる．

## 2. starカラムが保存できるように，ストロングパラメーターを設定
```ruby:controllers/books_controller.rb
private
def book_params
    params.require(:book).permit(:title, :body, :star)
end
```
## 3. viewのformの部分に追記
```erb
<div class="form-group position-static">
    <p>評価:</P>
    <div id="post_raty"></div> <!-- 星を出力するセレクタ -->
    <% if book.id.nil? %> <!-- 新規投稿か判別 -->
      <script>
          var elem = document.querySelector('#post_raty');
          var opt = {
              starOn: "<%= asset_path('star-on.png') %>",
              starOff: "<%= asset_path('star-off.png') %>",
              scoreName: 'book[star]',
          };
          raty(elem,opt);
      </script>
    <% else %>
      <%= render "output_star", book: book %>
    <% end %>
</div>
```
まず，`<div id='post_raty'></div>`という部分で，星を出力する場所を決める．
idに`post_raty`と設定することによって，これをJavascriptで認識する．
### 新規投稿の場合
新規投稿の場合，投稿と同時に星評価をしなければならない．
1.
```javascript
var elem = document.querySelector('#post_raty');
```
この部分で，星を表示させるセレクタを認識します。
2.
```javascript
var opt = {
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    scoreName: 'book[star]',
};
```
この部分では，以下のことをしている．
+ `starOn`オプションは，starが選択されているときに表示する画像の設定をする．
+ `starOff`オプションは，starが選択されていないときに表示する画像の設定をする．
+ `scoreName`オプションは，paramsでデータを送る際の名前を設定する．

今設定の場合は，book => {star: ~~~~~}として，parametersにデータを渡す．
3.
最後に，`raty(elem, opt)`を実行することによって，application.jsに設定しているraty関数が実行され，星評価を実装できる．

### 編集の場合
情報編集の場合，星評価をできないようにしなければならない．
そのため，星を表示するビューファイルの_output_star.html.erbの部分テンプレートを呼び出す．
このファイルについては，次の項目で示す．

# 星評価を表示する
星評価を表示する場所が複数ある場合には，_output_star.html.erbという部分テンプレートを作成することによって，簡単に実装することが出来る．
```erb
<div id="show_star-<%= book.id %>"></div>
<script>
    var elem = document.querySelector('#show_star-<%= book.id %>');
    var opt = {
        starOn: "<%= asset_path('star-on.png') %>",
        starOff: "<%= asset_path('star-off.png') %>",
        readOnly: true,
        score: <%= book.star %>
    };
    raty(elem,opt);
</script>
```
まず，`<div id="show_star-<%= book.id %>"></div>`という部分で，星を出力する場所を決める．
今回は，一覧ページでの出力も視野に入れ，idに変数のbook.idを指定した．
1.
`var elem = document.querySelector('#show_star-<%= book.id %>');`
この部分は，formと同じである．
2.
```javascript
var opt = {
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    readOnly: true,
    score: <%= book.star %>
};
```
この部分は，formの部分とオプションの設定が異なる．
+ `readOnly`オプションは，表示のみをする設定をする．
+ `score`オプションは，表示する星の数を設定する．

これによって，星の出力のみを行い，すでにレコードに登録されているbook.starカラムを参照することによって，星を表示している．

# Bootstrapとの併用について
```html
<div class="row">
  <div class="col-md-3 position-static">
    <div id="post_raty"></div>
  </div>
</div>
```
グリッドシステムとの併用をする場合は，`position-static`クラスを定義する．
このように設定することによって，halfオプションでのエラーを回避することが出来る．

# オプションの設定項目
説明内で紹介したオプションや関数以外の設定に関しては，以下のURLを参考にしてください．
https://github.com/wbotelhos/raty#options

また，それぞれの設定の公式チュートリアルは以下を参照すること．
https://github.com/wbotelhos/raty/blob/main/tutorial.md