旧ブログ(ISSEN)から移行しました

【Rails】enumを使用したselectボックスの作成(ransackで使用する際の注意点も)

【Rails】enumを使用したselectボックスの作成(ransackで使用する際の注意点も)

寺田拓真
寺田拓真6分で読めます

はじめに

この記事の概要

こんにちは、株式会社TOKOSのたくまです!
今回はenumを使用してselectボックスを作成する方法について紹介します

enumとは、数値のカラムに対してプログラム上で扱える別名を与えるものです。
数値に対して名前を与えることで可読性が上がります。
また、定義されている以外の値を保存できないようにしてくれます。
この他にもレコードを扱うのに便利な機能が多く、大変便利なメソッドです!

基本的なenumの使い方や実装方法については、以下のサイトが参考になると思います。

enumチュートリアル

この記事では初めにenumの仕組みを図解形式で分かり易く説明し、その後に実際にenum解説専用のアプリを作りながらenumを理解できます。実際にアプリを作ることによってどの場面でenumを使えば良いか理解しながら実装できる様になります。

pikawaka.com

このenumselectボックスを作成する際にも便利なので、これから紹介する方法をぜひお試しください!

例として、今回は下にあるような利用プランに関するselectボックスを作成していきます。

対象読者

  • enumを勉強中の初学者の方
  • enumを使ってセレクトボックスを作成したい方

selectボックス作成方法

enumを設定する

まずはselectボックスで使用するenumを設定します。
今回はユーザーの利用プランに関するカラム(plan)を持ったUserモデルに以下のような記述をします。

Ruby
# 0: 無料プラン, 1: スタンダードプラン, 2: プレミアムプラン
enum plan: { free: 0, standard: 1, premium: 2 }

これでenumが定義できました。

enum_helpの導入・ja.ymlに翻訳情報を記載

選択肢は日本語で表示させたいので、その下準備としてenum_helpというgemを導入します。
enum_helpとはenumで定義した値をI18n化させることができるgemです!

たくまたくま

I18nは Internationalization(国際化) の略だね! "I"と"n"の間に18文字あるから、こう略されているよ😎

enum_helpについて、下の記事に詳しい使用方法が記載されているので参照ください。

enumとenum_helpの使い方【rails】 - Qiita

はじめに enumとenum_helpについて enumって何?? モデルで数値のデータ型で定義しているカラムを、 文字列型として使えるようにすることができます。 例えば、0は男性、1は女性みたいな感じです。 定義方法 enumはモデルに定義する必要があります。 定義...

qiita.com

追加方法はGemfileに下記のように追記して、bundle installを行えばOKです!

Ruby
gem 'enum_help'

続いて、ja.ymlに翻訳情報を記述していきます。

これで下準備を完了です!
呼び出し方については後述します。

selectボックスを表示する

enumを設定したので、それを基にview側でselectボックスを作成しましょう!
今回はform_withを使用して作成します。
プルダウン形式のフォームは通常、下記のようにf.selectを用います。

ERB
<%= f.select カラム名, {'選択肢': DBに保存する値}, {オプション}, {classなどの要素} %>

これに倣って、enumを用いたselectボックスを作成すると下記のようになります。
Tailwind CSSでスタイルをあてています。)

ERB
<%= 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.user.plan.#{k}")の部分ですが、これはja.ymlの表記の通りに翻訳するというメソッドです。tの後の()内でどの階層にあるものかということを明記しています。
このように記述することで、先ほどja.ymlに記述した日本語の文字列を選択肢に表示させることができます。

これで、enumを使用したselectボックスを作成できました!

ransackでselectボックスを使用する

view側の記述を変更する

ここからは、ransackを用いて検索する際にselectボックスを使用する方法について紹介します。
ransackの基本的な使用方法については、以下のサイトをご覧ください。

ransackを使って検索機能がついたアプリを作ろう!

Railsの検索機能を簡単に作成できるgemのransackの使い方を解説しています。gemの導入方法から実際の使い方まで、この記事を読めばransackの使い方をマスターすることができます。アプリに検索機能をつけたい方は必見です。

pikawaka.com

ransackで検索条件を設定する際にenum型のカラムを設定し、selectを用いて検索することも可能です。
ただ、これまで紹介した方法で作成したselectボックスを使用して検索はできないので注意が必要です。

理由は、enumにより実際にDBに保存されているのは対応づけられたinteger(数値)であり、
ransackはその値に基づいて検索をかけているからです。

これまでに作成したselectボックスを検索条件に設定した際のHTML構造の画像をご覧ください。(chromeの検証ツールにて確認しています)

valueの値がenumで設定した名前(文字列)になっていることがお分かり頂けると思います。
この状態では、うまく検索できません。
valueの値に元のinteger(数値)を渡してあげる必要があります。

そのためには、下記のようにviewの記述を変更します。

変更前

ERB
<%= 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]" } %>

変更後

ERB
<%= 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)とすることで、利用プランをスタンダードプランとプレミアムプランのみ表示しています。

ERB
  <%= f.select :plan, User.plans.slice(:standard, :premium).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" %>

選択肢の特定の値を除外する

同じように特定の値を除外したい場合は、
exceptを使用することで実現できます!

except

exceptを使用することで、引数に設定した値以外を取得できます。
except(:premium)とすることで、利用プランを無料プランとスタンダードプランのみ表示しています。

ERB
  <%= f.select :plan, User.plans.except(:premium).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" %>

どちらも指定する値によっては、同じ選択肢を作成することも可能です。
ケースによって使い分けてみてください!

おわりに

今回はenumを使用したselectボックスの作成方法を紹介しました。
紹介した方法を用いることで、コードがすっきりして可読性も上がるのでおすすめです!
enumには他にも便利な機能が多くあるので、これからも勉強していこうと思います😎

この記事を書いた人

寺田拓真
寺田拓真

TOKOSのコーダー。このブログではコーディングに関する投稿をしています。トロたくが好きです。