railsお気に入り機能　一例

# お気に入り機能の実現
・ハートアイコンとそれに付属する数字の表示
・ハートアイコンを押す前に自分が押していなかったら数字を+１して、押していたのなら-1をする

# HTML
```show.html.rb
<div class="card-show" id="js-card-show" data-user-id="<%= @current_user.id %>" data-book-id="<%= @book.id %>">
      # この画面に来た時にユーザーが既にお気に入りしているのか否かで条件分岐
      <% if Like.find_by(impression_id: impressions.id, user_id: @current_user.id)%>
          
          <span data-liked="true" data-impression-id="<%= impressions.id %>" class="material-icons hart" >favorite</span>
          <span><%= impressions.likes.count %></span>
      <% else %>
          <span data-liked="false" data-impression-id="<%= impressions.id %>" class="material-icons">favorite</span>
          <span><%= impressions.likes.count %></span>
      <% end %>
</div>
``` 
```
data-user-id="<%= @current_user.id %>" data-book-id="<%= @book.id %>"
```
data-で始まる属性は、カスタムデータ属性といって、jquery,JavaScript内で値を取得できる形にしている
data-で始まる属性は、htmlとしての意味はないがJavaScriptやCSSで使うことができる

favoriteアイコンは[こちら]
(https://qiita.com/takish/items/9b65f1dcf36cc242357f)を使用しました

#### contrller
```books.contrller.rb
    def show
      @book = Book.find(params[:book_id])
      @user = User.find_by(id: @book.user_id)
      @impressions = @book.impressions
    end
```
### model
```like.rb
    belongs_to :user
    belongs_to :impression
```

```impression.rb
    has_many :likes
```

```user.rb
    has_many :likes
```
`user.rb`と`like.rb`が結びついているのはユーザー画面でお気に入りした投稿を観れるようにするため


## Jquery
#### application.html.erbの方にjqueryの読み込みを書いていない場合

```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
```

[【2018年版】jQuery最新の読み込みスクリプト「コピペOK＋裏技」]
(https://macoblog.com/jquery-saishin/)

```show.html.rb
#　jquery が使えるように読み込む
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
  $(function () {
    var userId = $("#js-card-show").data("user-id");
    var bookId = $("#js-card-show").data("book-id");

    $('.material-icons').on('click', function () {
      var self = $(this); 　　　　　// クリックされた要素を代入 
      var impressionId = self.data("impression-id");
      var hasMyLike = self[0].dataset.liked;
      if (hasMyLike === "true") {　
        $.ajax({                 // イフ文がtrueの場合
            url: '/likes/' + impressionId + '/destroy', // 正しい書き方ではない
            type: 'POST',         // 送信
            dataType: "json", // これ書かなかったら自動推察。この場合はなくても動いたです
            timespan: 1000, // 通信のタイムアウトの設定(ミリ秒)
            data: {                    //送るデータのカラムと中身                         
              '_method': 'delete',
              'impression_id': impressionId,
              'user_id' : userId,
              'book_id' : bookId,
            }
          }).done((data) => {                   // 成功したら
            $(this).removeClass('hart');          // ".hart"をクリックした要素から外す
            self.next()[0].innerText = (data.count).toString();
            self[0].dataset.liked = false;       // html上の`data-liked`をtrueからfalseへ
            console.log("success");   // 検証のconsoleで見れる
          })
          .fail((data) => {          // 失敗した時の処理
            console.log("fail");
          })
          .always((data) => {      //常に行われる処理
            console.log("always");
          });
      } else {                      // イフ文がfalseの場合
        $.ajax({
            url: '/likes/' + impressionId + '/create',
            type: 'POST',           // POSTが送信、GETが受信
            dataType: "json",                  
            timespan: 1000,                     
            data: {
              user_id : userId,
              impression_id : impressionId,
              book_id : bookId,
            }
          }).done((data) => {
            $(this).addClass('hart');        // class="hart"をクリックした要素に加える(.や#はいらない)
            self.next()[0].innerText = (data.count).toString();
            self[0].dataset.liked = true;
            console.log("success");
          })
          .fail((data) => {
            console.log(data);
            console.log("fail");
          })
          .always((data) => {
            console.log("always");
          });
      }

    });
  });
</script>

```

`var userId = $("#js-card-show").data("user-id");`
変数宣言してから代入。data属性を使ってrailsのデータをとってきてそれをjquery内で使える変数に代入
bookIdも同じ

`$('.material-icons').click(function () {` 
ブラウザ上で`class="material-icons"`をクリックした時イベントを起こすための`.click`イベント
idの場合は.(ドット)ではなく#を使う

`(hasMyLike === "true") `hasMyLikeという変数の中身に`true`という文字列を入れているので判定するための`true`も文字列として確実に認識させるために"で囲んでいる。

ajaxの条件分岐で参考にしました。ずっとfalseにデータが行き続けるのはこれで解決
JavaScript 忘れがちな　=== と == の違い
https://qiita.com/PianoScoreJP/items/e43d70ec188c6fed73ed

こちらは調べても何もわからなかった時に何か一つでもと思って実装しました☟
非同期通信（Ajax）をするときはタイムアウト処理を必ず入れてほしい(切実)
https://qiita.com/tonkotsuboy_com/items/d1b3cf45ae5135441f9b

```likesController.rb 
    def create
      user_id = params[:user_id].to_i
      book_id = params[:book_id].to_i
      impression_id = params[:impression_id].to_i
      like = Like.new
      like.user_id = user_id
      like.book_id = book_id
      like.impression_id = impression_id
      if like.save
        current_like_count = Like.where(book_id: book_id, impression_id: impression_id).size
        logger.debug(current_like_count)
        success_json_object = {
          'count' => current_like_count,
        }
        render :status => :ok, :json => success_json_object
      else
        failer_json_object = {'status' => 'failer'}    
        render :status => :internal_server_error, :json => failer_json_object
      end
   end
   
    # ライク削除処理
    def destroy
      impression_id = params[:impression_id].to_i //paramsは文字列なので別の場所で数値化
      user_id = params[:user_id].to_i             //メソッドの中で数値化できなかった
      book_id = params[:book_id].to_i
      like = Like.find_by(                        
        impression_id: impression_id,
        user_id: user_id,
        book_id: book_id
      )
      logger.debug "#{like.inspect}"          // ajaxがログにも影響しているのを確認した名残り
      logger.debug "-----------------------------------"
      if like
        if like.destroy
          current_like_count = Like.where(book_id: book_id, impression_id: impression_id).size
          success_json_object = {
            'count' => current_like_count,
          }
          render :status => :ok, :json => success_json_object  //データがtrueの時jsonとして発動？
        end
      end
    end
end
```

よんでくれてありがとう