某フリマサイトのコピーサイトをチーム開発しており、パスワードの表示に関して、JavaScriptを使って実装しておりました。
そんな中、動作確認をしていたところ、初回読み込み時のみJavascriptの記述が機能しないという問題が発生したので、その時の解決までの流れを纏めます。
#実装機能
今回実装していたのは、チェックボックスをチェックしたときにパスワードを表示する機能です。
-パスワード入力時画面
-チェックボックスをチェックした時の画面
#発生した問題
初回読み込み時のみ、意図した動作が行われない
動作確認時、初回読み込み時のみ、今回の機能がうまく動きませんでした。
その時は、記述にミスがあるのかと思い、確認しましたが、特に問題は見つかりませんでした。
そこで、再読み込みを行い確認したところ、しっかりと動作する。
そこで、色々と確認した結果、以下のことがわかりました!
#原因
まず、結論から申し上げます。
今回の問題の犯人は、[Turbolinks]でした!
「よし!解決!」と行きたいところでしたが、そもそも[Turbolinks]って、聞いたことはあるけど、よくわかってなかったので、調べました。
##『Turbolinks』とは
Asset Pipeline を活用しているアプリケーションにおいて、画面遷移を高速化するライブラリ
*Asset Pipeline:
JavaScriptやCSSのアセットを最小化 (minify: スペースや改行を詰めるなど) または圧縮して連結するためのフレームワーク。
Asset Pipelineは'sprockets'というgemによって実装され、デフォルトで有効になっています。
###『Turbolinks』の機能詳細
動作が高速になる理由は、画面全体を更新するのではなく、画面の一部だけを更新させているからです。
まず、一般的にブラウザがページを表示するときには、以下の順番で動作が行われます。
1.ページ自体の HTML をダウンロードする。
2.ページの中で参照されているスタイルシートや Javascript をダウンロードする。
3.ページをレンダリングする。
ページ内でスタイルシートなどの他のリソースを参照している場合は、ブラウザと Web サーバの間で複数の通信が行われます。
この動作を高速化するために登場した’Turbolinks’は、リンクのクリックイベントをフックし、Ajax リクエストに変換します。
そしてレスポンス(新しいページの HTML)を受け取ると、現在のページの 'title'と'body'を新しい HTML の'title' と'body'に交換します。
こうすることで、
また、History API を用いてコンテンツのキャッシュやブラウザ履歴の操作が行われるため、ブラウザの戻るボタンが押されたときにも違和感無く前のページの内容が復元されます。
###『Turbolinks』の注意点
上記メリットのある'Turbolinks'ですが、注意点があります。
####1.ページ読み込みを起点としたJavascriptは機能しない
通常であればページが読み込まれたタイミングで load イベントが発生しますが、Turbolinks によって画面が切り替わった場合は load イベントは発生しません。
その為、ページ読み込みを起点としたJavascriptは機能しなくなります。
今回はこちらが原因でした!!
####2.直接アクセスされた場合は、Turbolinksが発動しない
リンクを経ずに直接ページにアクセスされた場合や、ブラウザで再読み込みを行なった場合は、Turbolinksが発動せず、通常通り、ページの読み込みが行われます。
####3.別のスタイルシート/Javascriptを参照している場合は、効果が無い
ページごとに違いスタイルシートなどを参照している場合、ページ遷移を高速化させる力を発揮することが出来ません。
(「head」を読み込み直す必要があるので、通常と変わらない)
全てのページが Asset Pipeline で一つにまとめられたスタイルシートと Javascript を参照しているという前提があって初めて、Turbolinksは正常に機能することとなります!
#解決方法
今回の解決方法はいくつかありますが、Turbolinksの削除は避けたかったので、該当のページに遷移するlink_toの記述に追記しました!
*Turbolinksは、ページを移動するときに動くので、Turbolinksの起動を防ぐための記述は、遷移までのページに必要となります。(最初、よくわかっておらず、該当のフォームの箇所に記述しておりました。。。)
##1.部分的に無効化させる方法
<!-- (1) 特定のリンクのみ Turbolinks を無効化する -->
<a href="..." data-no-turbolink>...</a>
<%= link_to "..." ,"data-turbolinks":false %>
<!-- (2) 特定の範囲で Turbolinks を無効化する -->
<div data-no-turbolink>
<a href="...">...</a>
</div>
##2.全体で無効にする方法
1:Gemfile から「gem ’turbolinks’」を削除する。
2:app/assets/javascripts/application.js から「//= require turbolinks」を削除する。
3:app/views/layouts/application.html.erb の
javascript_include_tag や stylesheet_link_tag から
「"data-turbolinks-track" => true」を削除する。
#ちなみに。。(メモ)
##今回の記述内容
今回のJSの挙動はチェックボックスをクリックしたときにパスワードの属性をtextに切り替えることで実装してます。
$(function() {
const password = '#password';
const passcheck = '#reveal_password';
$(passcheck).change(function() {
if ($(this).prop('checked')) {
$(password).attr('type','text');
} else {
$(password).attr('type','password');
}
});
});
.single-main__container__form__frame
= form_for(@user, url: user_registration_path) do |f|
= render "devise/shared/error_messages", resource: @user
.form-group
= f.label :パスワード
%span.form-group__require 必須
= f.password_field :password,{autocomplete: "new-password",placeholder: "7文字以上の半角英数字",class:'form-group__input',id:"password"}
%p.form-group__info ※ 英字と数字の両方を含めて設定してください
.form-password-revelation-toggle
.checkbox-default
%input#reveal_password{type: "checkbox",class:"icon-check"}
%label{for: "reveal_password"} パスワードを表示する
.form-password-revelation-revealed-password-container
%span.form-password-revelation-revealed-password
#参照
Turbolinks
https://www.techscore.com/tech/Ruby/rails-4.0/turbolinks/
アセットパイプライン
https://railsguides.jp/asset_pipeline.html
How to disable turbolinks in Rails 5? #269
https://github.com/turbolinks/turbolinks/issues/269
『Turbolinks』って、なんぞ?
https://www.ryotaku.com/entry/2019/01/15/213420
turbolinksチートシート
https://qiita.com/morrr/items/54f4be21032a45fd4fe9
最後までご覧いただき、ありがとうございました!
今後も学習した事項に関してQiitaに投稿していきますので、よろしくお願いします!
記述に何か誤りなどございましたら、お手数ですが、ご連絡いただけますと幸いです。