Naomi's notebook

Naomi's notebook

Ruby on Rails tutorial +alpha(8)ストップウォッチの実装

注意:この記事はメモなので、この記事に書いてあることをやっただけでは同じものができません。(大体の雰囲気は書いてあると思います。)

注意:全くのweb開発初心者なので、間違っているところなどがあるかと思いますが、教えていただけると嬉しいです。

naomi-notebook.hatenablog.com

ストップウォッチを使って生活記録をつけられるようにします。開始時刻はデータベースに記録され、画面を閉じてもう一回開いても開始時刻からの時間が表示されているようにします。

まず、普通のタイマーをjavascriptで作ります。コントローラtimerを作り、get '/timer', to: 'timer#show'をルーティングします。このビューにタイマーを作ります。

javascriptでストップウォッチを作ってみる。忘備録 - Qiita これを参考にしました。

starttimeとtimetoaddをuserごとにデータベースに保存すると良さそうです。一つずつしかないので、usersデータベースに保存してしまいましょう。

rails g migration AddTimerToUsers timer_start:datetime timer_add:integer 
rails db:migrate

routesにpost '/timer', to: 'timer#edit'を追加し、editでデータベースに記録します。

【Rails】Rails⇔JavaScript間で時間データを渡す方法 - Qiita ここら辺も参考にしました。

とりあえずこれでタイマー機能ができました。viewとcontrollerを載せておきます。

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ストップウォッチで記録をつける</title>
</head>
<body>
    <div id="timer">00時間00分00</div>
    <button id="start">start</button>
    <button id="stop">stop</button>
    <button id="reset">reset</button>
</body>
</html>

<script>
(function(){
    'use strict';
    var timer = document.getElementById('timer');
    var start = document.getElementById('start');
    var stop = document.getElementById('stop');
    var reset = document.getElementById('reset');

    var startTime=<%=@user.timer_start ? @user.timer_start.to_f*1000 : 0 %>;//開始時刻を記録する
    var elapsedTime = 0;//経過時刻
    var timerId;//タイマーを止める用のタイマーのid
    var timeToadd=<%=@user.timer_add ? @user.timer_add : 0%>;
    var started=false;
    <% if @user.timer_start then %>
        var started=true;
        countUp();
    <% elsif @user.timer_add then %>
        elapsedTime = timeToadd;
        updateTimetText();
    <% end %>
    function updateTimetText(){//ミリ秒を時間:分:秒に直す
        var h = Math.floor(elapsedTime / 3600000);
        var m = Math.floor(elapsedTime %3600000 / 60000);
        var s = Math.floor(elapsedTime % 60000 / 1000);

        //2桁ずつ表示させる
        h = ('00' + h).slice(-2);
        m = ('00' + m).slice(-2); 
        s = ('00' + s).slice(-2);
        timer.textContent = h + '時間' + m + '分' + s;
    }


    //再帰的に使える用の関数
    function countUp(){
        timerId = setTimeout(function(){
            elapsedTime = Date.now() - startTime + timeToadd;
            updateTimetText()
            countUp();
        },1000);//一秒おきに実行
    }

    //todo:timer_startにtime_startを、timer_addにtime_addを記録
    function recordState(time_start,time_add){
        $.ajax({
            url: "timer",
            type: "POST",
            data: {timer_start:time_start,timer_add:time_add},
            dataType: "html"
        });
    }

    start.addEventListener('click',function(){
        started=true;
        startTime = Date.now();
        recordState(startTime,timeToadd);
        clearTimeout(timerId);
        countUp();
    });

    stop.addEventListener('click',function(){
        if(started){//タイマーが止まっている時は何もしない
            clearTimeout(timerId);
            timeToadd += Date.now() - startTime;
            recordState("nil",timeToadd);
            started=false;
        }else{
            console.log("stopの押し過ぎはやめてください")
        }
    });

    reset.addEventListener('click',function(){
        clearTimeout(timerId);
        elapsedTime = 0;
        timeToadd = 0;
        recordState("nil","nil");
        updateTimetText();
        started=false;
    });
})();
</script>
class TimerController < ApplicationController
    def show
        @user=current_user
        render "timer/show"
    end
    def edit
        params.permit(:timer_start,:timer_add)
        time=nil
        add=nil
        time=Time.at(params[:timer_start].to_i/1000).in_time_zone if params[:timer_start]!="nil" 
        add =params[:timer_add].to_i  if params[:timer_add]!="nil" 
        current_user.update_attributes(timer_start:time,timer_add:add)
    end
end

ここから、ログインしたユーザしか見られなかったり、生活記録を(今の時間-計測した時間)から(今の時間)までの長さでつけられるように書いていきます。

jQuery内からRailsのActionを叩く - Qiita 【Rails】ajax通信 -> 処理 -> redirect_toのやり方(remote: true/controller) - Qiita

これも参考にしました。

function postEvent(){
        var title=document.getElementById("title_form").value;
        var eventtype=document.getElementById("eventtype_form").value;
        var time=elapsedTime;
        $.ajax({
            url: "timer/new",
            type: "POST",
            data: {title:title,eventtype:eventtype,time:time},
            dataType: "text",
            success: function(data) {
                alert("行動記録が作成されました!");
            },
            error: function(data) {
                alert("エラーにより行動記録が作成されませんでした。");
            }
        });
    }
submit.addEventListener('click',postEvent);
def create_event
        time=(params[:time].to_i/1000).to_i
        params[:title]="睡眠" if params[:eventtype] == "1"
        params[:title]="食事" if params[:eventtype] == "2"
        params[:title]="服薬" if params[:eventtype] == "3"
        event_params={title:params[:title],eventtype:params[:eventtype],starttime:Time.now-time,endtime:Time.now}
        @event = current_user.events.build(event_params)
        if @event.save
            return "true"
        else
            return 
        end
    end

params[:title]="睡眠" if params[:eventtype] == "1"をもう一回書いているのがとても頭が悪い感じですが…(あとでヘルパーか何かにまとめ流べき)

とりあえずこんな感じで完成です。 あとはテストを書けば終わりです。

f:id:Naomi_Lilienthal:20200820184959p:plain
タイマーの様子