hidden_fieldの使い方

Railsで```hidden_field```を使ったので、内容整理のためメモ。
まず、```hidden_field```と```hidden_field_tag```は用途は似ているが使い方が違う。
```hidden_field```は```form_for```や```form_with```の中で使用するに対し、```hidden_field_tag```は一つだけ単体でパラメーターを渡したいときに使用する。
```hidden_field_tag```も```form_for```内で使用できないわけではない。
今回は```hidden_field```に焦点を当てることとする。

○実装の背景
ログインしているユーザーが残業申請フォームから一日分の残業申請できるようにする。
usersテーブルとattendancesテーブルが存在し、2つのテーブルは1対多の関係である。

```erb:/users/show.html.erb
<!-- 残業申請フォーム -->
<%= @date.each do |date| %>
      <div class ="test" id="<%= date.attendance_day %>">
        <h3>残業申請</h3>
        <%= form_for(date, url: sample_path, method: :post) do |f| %>
        <%= f.hidden_field :id, :value => date.id %> <!-- attendancesテーブルのidを渡す -->
        <%= f.hidden_field :user_id, :value => @user.id %>
          <table class="txt1 table table-bordered table-striped table-condensed">
            <thead>
              <tr>
                <th>日付</th>
                <th>曜日</th>
                <th>終了時間（必須）</th>
                <th>業務内容</th>
                <th>確認（必須）</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <!-- 日付 -->
                <td><%= date.attendance_day.month %>/<%= date.attendance_day.day %></td>
                <!-- 曜日 -->
                <td><%= @week[date.attendance_day.wday] %></td>
                <!-- 終了時間 -->
                <td><%= f.time_field :scheduled_end_time, class: 'form-control' %> </td>
                <!-- 業務内容 -->
                <td><%= f.text_field :business_outline, class: 'form-controll' %></td>
                <!-- 確認 -->
                <td>
                  <% if current_user.superior? %>
                    <%= f.select :instructor_test, [@superior], :include_blank => true %>
                  <% else %>
                    <%= f.select :instructor_test, @superior, :include_blank => true %>
                  <% end %>
                </td>
              </tr>
            </tbody>
          </table>
          <%= f.submit "残業を申請する", class: "btn btn-sm btn-primary" %>
        <% end %>
      </div>
    <% end %>
```
@dateにはログインしているユーザーの月初から月末までの勤怠データが格納されており、each文で繰り返し処理している。
レコードはattendancesテーブルの内容。
form_forでブロック変数fを定義し、f.hidden_fieldを2つ指定している。
第一引数にはパラメータで渡すname属性を指定するので、何でも良いが、わかりやすい名前にする。今回は```id```と```user_id```とする。
第二引数はvalue属性を指定するので、```id```の場所に```date.id```、```user_id```に```@user.id```とする。
```date.id```はattendancesテーブルのid(つまり月初から月末までの1日ごとのid)を、```@user.id```はusersテーブルのid（つまりログインしているユーザーのid)をvalueに指定している。
hidden_fieldで値をパラメーターで渡すときは上記のようにname属性とvalue属性を指定する。

```rb:attendances_controller.rb
  # 一日分の残業申請
  # users/show.html.erbのhidden_fieldのパラメータ取得
  def sample
    # 取得できるものは以下と同じ @user = User.find(params[:id])
    @user = User.find(params[:attendance][:user_id])
    @attendance = @user.attendances.find(params[:attendance][:id])
    # binding.pry
    if params[:attendance][:scheduled_end_time].blank? || params[:attendance][:instructor_test].blank?
      flash[:warning] = "必須箇所が空欄です。"
      redirect_to @user
    else
      @attendance.update_attributes(overtime_params)
      flash[:success] = "残業申請が完了しました。"
      redirect_to @user and return
    end
  end

```
アクションでhidden_fieldで渡されたパラメーターを受け取ることができる。
受け取る時の決まりとして```params[:モデル名][:渡したname属性]```である必要がある。

```rb
# 今回は @user = User.find(params[:id]) と、取得できるものは実質同じ
@user = User.find(params[:attendance][:user_id])
```
上記の@userはhidden_fieldで指定したname属性であるuser_idを受け取っている。
user_idの中身（value属性）は@user.idなので、ログインしているユーザーのidを取得している。

```rb
@attendance = @user.attendances.find(params[:attendance][:id])
```
上記の@attendanceもhidden_fieldで指定したname属性であるidを受け取っている。
idの中身（value属性）はdate.idなので、月初から月末までの残業申請したい日付のidを取得している。

```erb
params[:attendance][:scheduled_end_time]
params[:attendance][:instructor_test]

<!-- users/show.html.erb の一部 -->
<td><%= f.time_field :scheduled_end_time, class: 'form-control' %> </td>
<td><%= f.select :instructor_test, [@superior], :include_blank => true %></td>
```
上記はhidden_fieldでパラメーターとして値を渡していないが、値が受け取れる。
なぜなら、form_for内でf.time_fieldのようにしてscheduled_end_timeを指定しているから。

**以下は失敗例**

```rb
params[:attendance][:scheduled_end_time].blank?
# のところを↓に変更すると...
@attendance.scheduled_end_time.blank?
```
上記の```@attendance.scheduled_end_time```では値がnilになり取得できない。
これはscheduled_end_timeがDBにすでに保存されていれば取得できるが、今回は申請前の残業申請フォームの「終了時間」を入力時点での値を取得したいので、```params[:attendance][:scheduled_end_time]```とする必要がある。