はじめに
この記事の概要
こんにちは、株式会社TOKOSのたくまです!
今回はenumを使用してselect ボックスを作成する方法について紹介します
enumとは、数値のカラムに対してプログラム上で扱える別名を与えるものです。
数値に対して名前を与えることで可読性が上がります。
また、定義されている以外の値を保存できないようにしてくれます。
この他にもレコードを扱うのに便利な機能が多く、大変便利なメソッドです!
基本的なenumの使い方や実装方法については、以下のサイトが参考になると思います。
このenumはselect ボックスを作成する際にも便利なので、これから紹介する方法をぜひお試しください!
例として、今回は下にあるような支払日に関するselectボックスを作成していきます。
対象読者
- enumを勉強中の初学者の方
- enumを使ってセレクトボックスを作成したい方
selectボックス作成方法
enumを設定する
まずはselectボックスで使用するenumを設定します。
今回はユーザーの利用プランに関するカラム(plan)を持ったUserモデルに以下のような記述をします。
# 1: 無料プラン, 2: スタンダードプラン, 3: プレミアムプラン
enum plan: { free: 1, standard: 2, premium: 3 }
これでenumが定義できました。
enum_helpの導入・ja.ymlに翻訳情報を記載
選択肢は日本語で表示させたいので、その下準備としてenum_help というgemを導入します。
enum_helpとはenumで定義した値をI18n化させることができるgemです!
I18nはInternationalization (国際化)の略だね!
“I”と”n”の間に18文字あるから、こう略されているよ😎
enum_help について、下の記事に詳しい使用方法が記載されているので参照ください。
追加方法はGemfileに下記のように追記して、bundle install を行えばOKです!
gem 'enum_help'
続いて、ja.ymlに翻訳情報を記述していきます。
これで下準備を完了です!
呼び出し方については後述します。
selectボックスを表示する
enumを設定したので、それを基にview側でselect ボックスを作成しましょう!
今回はform_withを使用して作成します。
プルダウン形式のフォームは通常、下記のようにf.select
を用います。
<%= f.select カラム名, {'選択肢': DBに保存する値}, {オプション}, {classなどの要素} %>
これに倣って、enum を用いたselect ボックスを作成すると下記のようになります。
( tailwindcss でスタイルをあてています。)
<%= f.select :plan, User.plans.keys.map { |k| [t("enum.user.plan.#{k}"), k] }, { include_blank: "指定なし" }, class: "mb-3 sm:mb-0 mr-9 border border-line-200 rounded-[3px] rounded-[3px] py-3 pl-6 w-52 h-12 font-bold" %>
記述を詳しく説明します。
plan はカラム名になります。
その次のUser.plans で支払日のenumをハッシュの形で取得しています。
この時、モデルに対してカラムは複数形であることに注意して下さい。
続くkeys で取得したハッシュのキーを配列の形で取得しています。
その後のmap メソッドで新たに配列を生成しています。
『 t(“enum.project.salary_month.#{k}”) 』の部分ですが、これはja.ymlの表記の通りに翻訳するというメソッドです。tのあとの()内でどの階層にあるものかということを明記しています。
このように記述することで、先ほどja.ymlに記述した日本語の文字列を選択肢に表示させることができます。
これで、enum を使用したselect ボックスを作成することができました!
ransackでselectボックスを使用する
view側の記述を変更する
ここからは、ransackを用いて検索する際にselectボックスを使用する方法について紹介します。
ransack の基本的な使用方法については、以下のサイトをご覧ください。
ransackで検索条件を設定する際にenum型のカラムを設定し、select を用いて検索することも可能です。
ただ、これまで紹介した方法で作成したselect ボックスを を使用して検索はできないので注意が必要です。
理由は、enum
により実際にDBに保存されているのは対応づけられたinteger(数値)であり、
ransackはその値に基づいて検索をかけているからです。
これまでに作成したselect ボックスを検索条件に設定した際のHTML構造の画像をご覧ください。(chromeの検証ツールにて確認しています)
valueの値がenumで設定した名前(文字列)になっていることがお分かり頂けると思います。
この状態では、うまく検索することができません。
value の値に元のinteger(数値)を渡してあげる必要があります。
そのためには、下記のようにviewの記述を変更します。
変更前
<%= f.select :plan_eq, User.plans.keys.map { |k| [t("enum.user.plan.#{k}"), k] }, { include_blank: "プラン" }, { class: "text-[#9A7E7E] form-select min-w-[120px] ml-4 rounded-[3px] border border-[#9A7E7E]" } %>
変更後
<%= f.select :plan_eq, User.plans.keys.map.with_index { |k, i| [t("enum.user.plan.#{k}"), i] }, { include_blank: "プラン" }, { class: "text-[#9A7E7E] form-select min-w-[120px] ml-4 rounded-[3px] border border-[#9A7E7E]" } %>
ポイントは、mapメソッドの後ろにwith_index をくっつけ、第二引数で要素の添字を変数 i として取得していることです。
このように記述することで、変数 i (数値)がvalueに渡され、無事に検索できるようになります。
その他
選択肢に特定の値だけを表示する
例えば、enumの特定の値だけを表示させたい時には、
sliceを使用することで実現できます!
slice
slice を使用することで、引数に設定した値だけを取得することができます。
『 slice(:standard, :premium) 』とすることで、利用プランをスタンダードプランとプレミアムプランのみ表示しています。
<%= f.select :plan, User.plans.slice(:standard, :premium).keys.map { |k| [t("enum.project.salary_month.#{k}"), k] }, { include_blank: "指定なし" }, class: "mb-3 sm:mb-0 mr-9 border border-line-200 rounded-[3px] rounded-[3px] py-3 pl-6 w-52 h-12 font-bold" %>
選択肢の特定の値を除外する
同じように特定の値を除外したい場合は、
except を使用することで実現できます!
except
except を使用することで、引数に設定した値以外を取得することができます。
『 except(:premium) 』とすることで、利用を無料プランとスタンダードプランのみ表示しています。
<%= f.select :plan, User.plan.except(:premium).keys.map { |k| [t("enum.project.salary_month.#{k}"), k] }, { include_blank: "指定なし" }, class: "mb-3 sm:mb-0 mr-9 border border-line-200 rounded-[3px] rounded-[3px] py-3 pl-6 w-52 h-12 font-bold" %>
どちらも指定する値によっては、同じ選択肢を作成することも可能です。
ケースによって使い分けてみてください!
おわりに
今回はenum を使用したselect ボックスの作成方法を紹介しました。
紹介した方法を用いることで、コードがすっきりして可読性も上がるのでおすすめです!
enumには他にも便利な機能が多くあるので、これからも勉強していこうと思います😎
Railsに関して今回紹介したenum以外にも知識を深めたいという方は以下の書籍がおすすめです。
実務にも役立つ情報が多くあり、Rails初学者の方の手助けになってくれる一冊です。