Rails初学者がSetIntervalとTurbolinksの狭間で困った(ている)話

# あらすじ
簡易チャットアプリを作成中。
特定のページにsetIntervalとAjaxを用いたメッセージの自動更新を実装しようとしたところ、
アプリの全ページにsetIntervalが作動してしまい、特定ページ以外で無限のエラーメッセージが生じ悩まされることに...。

![gif.gif](https://qiita-image-store.s3.amazonaws.com/0/158026/801afb96-4868-782d-2e11-eace92bdfb2e.gif)

# version
Programming歴: 65日目
Ruby:　2.3.1
Rails:　5.0.1

# 原因

調べて見たところ、
Railsにデフォルトで搭載されているTurbolinksという機能のせいで、
一度読み込まれたJavaScriptのプロセスが、他のページでも生き続けてしまうことが原因でした。

> とあるページでsetIntervalするとどのページに行っても止まらない、POSTしたりして止まっても今度は再開すべきページで再開しない、という事故が簡単に起きます。
>これはPOSTやPUTをしてjsの再読み込みが行われるまでページ遷移してもjsのプロセスがずっと生き続ける為です。（引用：[「Turbolinksさんと上手く付き合う10の方法」](http://qiita.com/seri_k/items/164accd9ef8ddb4a942e)）

問題解決には、Turbolinksさんをどうにかする必要があるみたいです、

# Turbokinksとは
ざっくりいうと、ウェブアプリ上でページを移動する際、新規ページ全体をリロードするのではなく、必要部分のみajaxを使って書き換えてくれるもの。これによってページ移動を高速化している。
現在のRailsにデフォルトでついている機能みたいですね。

詳細な解説は、以下の記事・サイトがわかりやすくオススメです。
・[KRAY「Rails 4のturbolinksについて最低でも知っておきたい事」](http://kray.jp/blog/must-know-about-turbolinks/)
→図がわかりやすく、ajaxでの書き換えのイメージが掴めます。
・[TECHSCORE 「6. Turbolinks」](http://www.techscore.com/tech/Ruby/rails-4.0/turbolinks/)
→解説が丁寧でわかりやすいです。
・[Qiita「Turbolinksさんと上手く付き合う10の方法」](http://qiita.com/seri_k/items/164accd9ef8ddb4a942e)
→Turbolinksでの基本的な注意点がまとまっています。
・[seri::diary「今更ながらTurbolinksを初めて仕事で使ってみたので色々調べてみた」](http://serihiro.hatenablog.com/entry/2014/08/11/234419)
→上記記事の筆者seri_kさんのブログ。Turbolinks以外の記事も非常に参考になります。

# 解決策
## ① TurbolinksをOFFにし、特定のページに個別でJSを当てる
ベストかどうかはわかりませんが、これが一番手っ取り早いです。
まずTurbolinksをOFFにし、その上で特定のページのみに適用させたいJSを個別に当てます。

### 手順1. Turbolinksのgemを削除する

```ruby:Gemfile
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks' #削除する
```
削除後に`bundle install`をお忘れなく。

```:terminal
$ bundle install
```

### 手順2. application.jsを編集する(Turbolinksの削除）

```application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks #削除する
//= require_tree .
```

### 手順3. application.html.erb から turbolinks を削除する
Before

```application.html.haml
= javascript_include_tag 'application', { turbolinks: { track: true } }
```

After

```application.html.haml
= javascript_include_tag 'application'
```
ちなみにhamlで記述しています。

ここまで、1~3の手順で、TurbolinksをOFFにすることができました。
参照：[Rails 4 で turbolinks をオフにする方法](http://qiita.com/kazz187/items/12737363d62b9c91993c)

### 手順4. application.jsを編集する（stubを用いて記述）

```application.js
//= require jquery
//= require jquery_ujs
//= require_tree .
//= stub reload #reload.jsは特定のページのみに適用させたい
```
「require_tree .」によって、application.js以下のディレクトリに存在するjsファイルが全て読み込まれる。
特定のページのみに適用させたいjsファイルはstubを用いて除外する。

### 手順5. JSを適用させたいviewファイルにjavascript_include_tagを記述する。

```messages/index.html.haml
= javascript_include_tag 'reload'
// JSを適用させたいviewファイルにjavascript_include_tagを記述する。
.chat
  .chat-side
    = render "partials/user-info"
    = render "partials/chat-groups"

  .chat-main
    = render "chat-main"

    .chat-body
      %ul.chat-messages
        = render @messages

    .chat-footer
      = render "chat-footer"
```

### 手順6. config/assets.rbに追記

```config/assets.rb
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.precompile += %w( reload.js )  #追記する
```

これで、特定のページ（messages/index）のみに、特定のJS(reload.js)が当たるようになりました。

## ②「Turbolinksさんと上手く付き合う10の方法」の[「3. setIntervalは慎重に使う」](http://qiita.com/seri_k/items/164accd9ef8ddb4a942e#3-setinterval%E3%81%AF%E6%85%8E%E9%87%8D%E3%81%AB%E4%BD%BF%E3%81%86)を実行

```
$(document).on 'page:change' ->
  if repeatable_condition # setIntarvalをセットする条件。特定のDOMがあるとか
    if window.set_timer_on == null 
      window.timer = setInterval('something_method()',3000)
  else if window.set_timer_on? # setIntarvalを動かしたくないページに来てtimerが動いる場合    
    clearInterval(window.timer)
    window.timer = null
```

記事では、上記のようなコードでTurbolinksとSetintervalの併用ができるとのことでしたが、
試行錯誤して見たものの、うまくいかず。Setintervalがどこのページでも作動してしまいました。
clearIntervalの挙動やJSにおけるグローバル変数など勉強する必要がありそうです。
以下は試行錯誤の上、試して見たコードです（うまく働かない。）

```reload.js
function auto_reload(){
(中略)
}

(中略)
$(document).on("turbolinks:load",function() {
  if (document.getElementsByClassName("chat").length == 1) {
  //　chatクラスが存在する場合、以下を行う。
    var id = setInterval(auto_reload, 1000);
  } else if (document.getElementsByClassName("chat").length == 0) {
  // chatクラスが存在しない場合、以下を行う。  
  clearInterval(id);
  }
});
```

# 参考リンク
・[KRAY「Rails 4のturbolinksについて最低でも知っておきたい事」](http://kray.jp/blog/must-know-about-turbolinks/)
・[TECHSCORE 「6. Turbolinks」](http://www.techscore.com/tech/Ruby/rails-4.0/turbolinks/)
・[Qiita「Turbolinksさんと上手く付き合う10の方法」](http://qiita.com/seri_k/items/164accd9ef8ddb4a942e)
・[seri::diary「今更ながらTurbolinksを初めて仕事で使ってみたので色々調べてみた」](http://serihiro.hatenablog.com/entry/2014/08/11/234419)