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対多の関係である。
<!-- 残業申請フォーム -->
<%= @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属性を指定する。
# 一日分の残業申請
# 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属性]
である必要がある。
# 今回は @user = User.find(params[:id]) と、取得できるものは実質同じ
@user = User.find(params[:attendance][:user_id])
上記の@userはhidden_fieldで指定したname属性であるuser_idを受け取っている。
user_idの中身(value属性)は@user.idなので、ログインしているユーザーのidを取得している。
@attendance = @user.attendances.find(params[:attendance][:id])
上記の@attendanceもhidden_fieldで指定したname属性であるidを受け取っている。
idの中身(value属性)はdate.idなので、月初から月末までの残業申請したい日付のidを取得している。
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を指定しているから。
以下は失敗例
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]
とする必要がある。