3
1

More than 3 years have passed since last update.

選択肢の「その他」を選んだ時のテキスト入力

Last updated at Posted at 2020-01-29

フォームで選択肢を実装した場合、その他項目を設けてその他が選択された時はテキスト入力を必須とする実装をしたい時がある。
割とどこにでもある実装だが、バリデーションも含めてちゃんと実装しようとすると、「あれ、どうやるんだっけ?」となったのでメモとして残す。

概要

例えば会員登録するユーザーの職業情報を得るために、いくつか選択肢を用意し、選択肢に当てはまらない場合はフリーテキスト入力を必須となるようにしたい。
その場合、フリーテキスト欄をその他が選択された場合だけ表示、それ以外の場合は非表示という実装をJavaScriptで行う以外に、Modelのvalidationにも記述する必要がある。
選択できる職業は、エンジニア、マーケッター、デザイナー、オペレーション、マネジメント、その他の6種類とし、その他が選択された時だけフリーテキスト欄入力を必須とする。

Schema

テーブルのカラムには、下記の2つのカラムをつける。(カラムの追加方法などはここでは省略)
db/schema.rb

create_table "users", force: :cascade do |t|
  t.integer "job", default: 0, null: false, comment: "職種"
  t.string "other_jobs", comment: "その他の職種"
end

jobsはenum管理するのでintegerで登録する。

Form

次にformに入力項目を追加する。(form_withの引数は適当)
views/users/new.html.slim


= form_with(model: user, url: registration_path, method: :post) do |form|
  = form.label :job
  = form.select :job, User.jobs_i18n.invert, {}, required: true
  = form.text_field :other_jobs, required: true, class: 'other_jobs-input', placeholder: '職種を入力してください'

User.jobs_i18n.invertは選択肢としてjobsのenumを一覧にして日本語化し、かつenumのhashのkey, valueを逆転させる。
これで選択肢の表示名にenumのkeyの日本語名を、valueにkeyをセット出来る。

JQuery

Formの表示・非表示を動的に行うためJQueryで操作を行う。


  $(function() {
    $(".other_jobs-input").hide();
  });
  // 選択肢の変更を検知してイベントを発生させる。
  $('select[name="user[job]"]').change(function() {
    if ($(this).val() === 'others')
      $(".other_jobs-input").show();
    else
      $(".other_jobs-input").hide();
  });

Model

最後にModelのコードを。


class User < ApplicationRecord
  validates :other_jobs, presence: true, if: -> { self.others? }
  validates_presence_of %i(
    job
  )

  before_validation :other_jobs_validation

  enum job: {
    engineer:   0,
    marketter:  1,
    designer:   2,
    operation:  3,
    management: 4,
    others:     5
  }

  private

  def other_jobs_validation
    self.other_jobs = "" unless self.others?
  end

まずenumを用いて選択肢管理を行う。
jobは必須項目としたいのでvalidates_presence_ofを使いvalidationをかける。

また、jobothersが選択された時はother_jobsを必須としたいので、if:オプションにlambdaを使ってbooleanを返すブロックを渡す。
こうすることで、職業選択欄でその他が選択された時にテキスト入力を必須と出来る。

逆にその他以外が選択された時はother_jobsに値が入っていて欲しくない。
そこでother_jobs_validationを定義し、before_validationに渡すことで目的を果たすことが出来る。

3
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1