Help us understand the problem. What is going on with this article?

hidden_fieldの使い方

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

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

/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属性を指定するので、何でも良いが、わかりやすい名前にする。今回はiduser_idとする。
第二引数はvalue属性を指定するので、idの場所にdate.iduser_id@user.idとする。
date.idはattendancesテーブルのid(つまり月初から月末までの1日ごとのid)を、@user.idはusersテーブルのid(つまりログインしているユーザーのid)をvalueに指定している。
hidden_fieldで値をパラメーターで渡すときは上記のようにname属性とvalue属性を指定する。

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属性]である必要がある。

# 今回は @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]とする必要がある。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away