フォーム欄の<label>と<input>の関係性

フォーム欄のlabelとinputの関係性

下記のようなフォーム欄があるviewファイルでテスト1のようなコードでテストを行なった場合、エラー1のように表示される場合。

[app/viewa ファイル]

<%= form_with model: board, local: true do |f| %>
    <%= render 'shared/error_messages', { object: f.object } %>
    <div class="form-group">
      <%= f.label :title %>
      <%= f.text_field :title, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :body %>
      <%= f.text_area :body, class: "form-control", rows: "10" %>
    </div>
    <div class="form-group">
      <%= f.label :image  %>
      <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %>
      <%= f.hidden_field :image_cache %>
    </div>
    <div class="form-group">
        <%= image_tag board.image.url, id: :img_prev %>
      <script type="text/javascript">
        $(function() {
          function readURL(input) {
              if (input.files && input.files[0]) {
              var reader = new FileReader();
              reader.onload = function (e) {
          $('#img_prev').attr('src', e.target.result);
              }
              reader.readAsDataURL(input.files[0]);
              }
          }
          $("#board_img").change(function(){
              readURL(this);
          });
        });
      </script>
    </div>
    <%= f.submit (t 'defaults.create'), class: "btn btn-primary" %>
<% end %>
[テスト1 ファイル]

it '掲示板が作成できること' do
    fill_in 'タイトル', with: 'テストタイトル'
    fill_in '本文', with: 'テスト本文'
    file_path = Rails.root.join('spec', 'fixtures', 'example.jpg')
    attach_file "サムネイル", file_path
    click_button '登録する'
    expect(current_path).to eq boards_path
    expect(page).to have_content('掲示板を作成しました'), 'フラッシュメッセージ「掲示板を作成しました」が表示されていません'
    expect(page).to have_content('テストタイトル'), '作成した掲示板のタイトルが表示されていません'
    expect(page).to have_content('テスト本文'), '作成した掲示板の本文が表示されていません'
end
[エラー1]

Capybara::ElementNotFound: Unable to find file field "サムネイル" that is not disabled

  0) 掲示板 掲示板のCRUD 掲示板の作成 ログインしている場合 掲示板が作成できること
     Failure/Error: attach_file "サムネイル", file_path      # サムネイルというlebelがあるフィールドにfile_pathを挿入したらエラーが起きた

     Capybara::ElementNotFound:          # Capybara::ElementNotFoundという例外クラス
       Unable to find file field "サムネイル" that is not disabled           # サムネイルというフィールドが無い

     [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_nested_crud_nested_2_nested_2_掲示板が作成できること_490.png


     # ./spec/system/boards/board_spec.rb:103:in `block (5 levels) in <top (required)>'

viewファイルにも実際にサーバーを起動した時のブラウザにも画像挿入のフィールドが存在し、動作に問題がないのにテストでエラーが起きてしまう。 これは、テストで利用している[Capybara Gem]が見ているのは、viewファイルではなくブラウザで表示されるhtmlの為。 Capybaraの動作順序は以下のようになる。
ブラウザのhtmlで[サムネイル]というlabelを探す。


[サムネイル]というlabelに関連したフィールドに、[file_path]という画像を挿入する。


今回発生しているエラーの原因は、labelとフィールドに関連性がないことが原因。([サムネイルというlabelを探せるがそれに関連しているフィールドが存在しない。])
htmlでlabelとinputに関連性をもたらすには、inputにid属性、labelにfor属性(inputのid属性と同じもの)を付与しなければならない。
今回のviewファイルでは、以下のようになっている。(labelとinputでforの属性名とidの属性名が違う)

[app/views ファイル]

<div class="form-group">
      <%= f.label :image  %>
      <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %>
      <%= f.hidden_field :image_cache %>
</div>

下記のように修正することでテストエラーを解消できる。

[app/views ファイル]

<div class="form-group">
      <%= f.label :image, for: :board_img  %>
      <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %>
      <%= f.hidden_field :image_cache %>
</div>


[補足]
以下のようにlabelにfor属性、inputにid属性を付与しない場合は、for属性名もid属性名も[board_board_image]になる。

<%= form_with model: board do |f| %>
    <%= f.label :board_image %>
    <%= f.file_field :board_image %>
<% end %>

参考記事:

<label> - HTML: HyperText Markup Language | MDN