mywork1868
@mywork1868

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【Ruby on rails】勤怠管理システムの退勤ボタンだけ保存されない

解決したいこと

現状:勤怠管理システムの退勤ボタンが、データベースを更新した直後一回しか反応しない
目標:出勤ボタンを押したら退勤ボタンに切り替わり、退勤の時刻として保存される

発生している問題・エラー

ビューは現状このような状態です
スクリーンショット 2024-06-21 113555.png

#<ActionController::Parameters {"authenticity_token"=>"cfqOM3oTSzD-AoNTQ-C7QOsqyg2cGc2WOQB00HHpeRc6G6TAWm_aO9BcgvF8trJBkBLLyhsonS0HqoClhBJWPQ", "commit"=>"出勤", "controller"=>"attendances", "action"=>"create"} permitted: false>
pry(#<AttendancesController>)> last_attendance
=> #<Attendance:0x00007f7fd4eeb0f0
 id: 5,
 user_id: 1,
 clock_in_at: Fri, 21 Jun 2024 10:40:00.369834000 JST +09:00,
 clock_out_at: Fri, 21 Jun 2024 10:40:01.539881000 JST +09:00,
 created_at: Fri, 21 Jun 2024 10:40:00.373485000 JST +09:00,
 updated_at: Fri, 21 Jun 2024 10:40:01.548026000 JST +09:00>
pry(#<AttendancesController>)> @attendance
#<Attendance:0x00007f7fd4cebf20
 id: nil,
 user_id: 1,
 clock_in_at: nil,
 clock_out_at: nil,
 created_at: nil,
 updated_at: nil>

該当するソースコード

<%= form_for(@attendance, url: attendances_path, method: :post) do |f| %>
  <% if (!@is_clocked_in && !@is_clocked_out) || (@is_clocked_in && @is_clocked_out) %>
    <%= f.submit "出勤", class: "btn btn-primary" %>
  <% elsif @is_clocked_in && !@is_clocked_out %>
    <%= f.submit "退勤", class: "btn btn-primary" %>
  <% end %>
<% end %>

<table>
  <tr>
    <th>出勤時刻</th>
    <th>退勤時刻</th>
  </tr>
  <% @attendances.each do |attendance| %>
    <tr>
      <td><%= l attendance.clock_in_at unless attendance.clock_in_at.nil? %></td>
      <td><%= l attendance.clock_out_at unless attendance.clock_out_at.nil? %></td>
    </tr>
  <% end %>
</table>
class AttendancesController < ApplicationController
  def new
    @pattern = WorkPattern.find_by(id: current_user.work_pattern_id)

    @attendance = current_user.attendances.build
    @attendances = current_user.attendances

    @feed_items = current_user.today_feed.paginate(page: params[:page])

    last_attendance = current_user.today_attendance

    @is_clocked_in = clock_in?(last_attendance)
    @is_clocked_out = clock_out?(last_attendance)

    @latest_attendance = current_user.attendances.last
  end

  def create
    last_attendance = current_user.today_attendance
    is_clocked_in = clock_in?(last_attendance)
    is_clocked_out = clock_out?(last_attendance)
    #binding.pry
    if (!is_clocked_in && !is_clocked_out) || (is_clocked_in && is_clocked_out)
      last_attendance = current_user.attendances.build(clock_in_at: Time.zone.now)
      flash[:success] = "出勤しました"
    elsif is_clocked_in && !is_clocked_out
      last_attendance.clock_out_at = Time.zone.now
      flash[:success] = "退勤しました"
    end
    
    if last_attendance.save
      redirect_to root_path
    else
      @feed_items = []
      flash.clear
      render 'attendances/new'
    end
  end

  def edit
  end

  def update
  end

  def index
  end
end
class CreateAttendances < ActiveRecord::Migration[7.0]
  def change
    create_table :attendances do |t|
      t.integer :user_id
      t.datetime :clock_in_at
      t.datetime :clock_out_at

      t.timestamps
    end
  end
end

自分で試したこと

ifの部分に問題があるのかとerbを書き換え、無理やり退勤ボタンを表示させて押してみましたが、出勤時間の部分に表示されてしまいました。

0

2Answer

細かい所は見ていないのでなんとも言えないけど、退勤はレコードの更新だからupdateメソッドに置くのでは?

1Like

Comments

  1. @mywork1868

    Questioner

    ご回答ありがとうございます。
    出勤も退勤も記録として残しておきたいのでcreateかと思って記載しておりました。
    updateメソッドは、既に記録されている出退勤時刻を修正したいときに使用する予定でした。updateは退勤と内容修正両方に使えるものなのでしょうか?

  2. 退勤も内容修正もレコードの更新なので両方ともupdateメソッドに渡せます。但しこの場合、パラメータによる分岐は必要です。
    また個人的には既存のやつだと、出勤時と退勤時でそれぞれレコードを作成するため管理が大変になるのではと感じました。ただ、仕様とかはよく知らないのでそれに合わせた方がいい気がします。
    自分が考える一連のフローは下記です。

    1. createメソッドでレコードを作成すると同時に、出勤時刻を記録する(退勤時刻は空データである)
    2. 退勤時、1で作成したレコードのオブジェクトのパラメータに”退勤”を用意し、updateメソッドに渡し、そのレコードの退勤時刻を更新する(オブジェクトは@attendancesのattendanceから取得できる)。そして、updateメソッドでパラメータによる条件分岐を行い、退勤時刻を現在時刻に更新。
    3. 勤怠を間違えた時、@attendancesから対象のattendanceオブジェクトを選択。そして、そのオブジェクトをeditメソッドに渡し、オブジェクトの中にある出勤時刻と退勤時刻を更新。その後、そのオブジェクトをupdateメソッドに渡す。(渡す際はパラメータに”修正”を渡す)そして、updateメソッドでパラメータによる条件分岐を行い、オブジェクトによる更新を行う。
      def create
        @attendance = current_user.attendances.build(clock_in_at: Time.zone.now)
        if @attendance.save
          flash[:success] = "出勤しました。"
          redirect_to root_url
        else
          flash.now[:danger] = "出勤記録に失敗しました。"
          render 'new'
        end
      end
    
      def edit
        # edit ビューは単純にフォームを表示
      end
    
      def update
        if params[:commit] == "退勤"
          if @attendance.update(clock_out_at: Time.zone.now)
            flash[:success] = "退勤しました。"
            redirect_to attendances_path
          else
            flash.now[:danger] = "退勤記録に失敗しました。"
            render 'edit'
          end
        elsif params[:commit] == "修正"
          if @attendance.update(attendance_params)
            flash[:success] = "打刻情報を修正しました。"
            redirect_to attendances_path
          else
            render 'edit', status: :unprocessable_entity
          end
        end
      end
    

    ただ、これもcreateやupdateやeditと書いていますが最低限のCRUDなので、あくまで一例として出しています。

  3. @mywork1868

    Questioner

    コメントありがとうございます。
    管理が大変になってしまうのですね、アドバイスいただきありがとうございます!

直接この回答とは関連しないかもしれませんが
attendanceのモデルのメソッドに

ruby
def before_working?
  !@is_clocked_in && !@is_clocked_out
end

def working?
  @is_clocked_in && !@is_clocked_out
end

def worked?
  @is_clocked_in && @is_clocked_out
end

みたいなの書いておくと、Viewの実装とかの条件分岐で見通しが良いのでおすすめです。

0Like

Your answer might help someone💌