自作アプリを作成しているときに、管理者機能として、フォームからのお問い合わせの対応ステータスを更新する機能があったらいいなと思い、調べながら実装してみたので、メモしておきます!
前提
構成(モデル等は生成済の前提で進めます)
-
MODEL (FormInquiry)
- t.integer "user_id"
- t.text "content"
- t.integer "response_status", default: 0
- t.datetime "created_at"
- t.datetime "updated_at"
-
CONTROLLER (form_inquiries)
- 問い合わせ一覧(index action)
- 問い合わせ詳細(show action)
- 対応ステータス更新(update action)
-
VIEWS
- 問い合わせ一覧(index.html)
- 問い合わせ詳細(show.html)
ライブラリ
- enum_help(enumをI18n化するgem)
- devise(ユーザー/管理者認証)
その他
- 会員(エンドユーザー)をUser、管理者をAdminとしてそれぞれテーブルを作成しています。
- 会員からフォームで問い合わせを受け付けると、管理者の問い合わせ一覧画面に表示されます。
- 管理者は問い合わせ詳細画面を開き、対応ステータス(未対応/対応中/対応済)の更新を行えます。更新すると、フラッシュメッセージが表示され、問い合わせ一覧のステータスも更新されます。
環境
ruby 2.6.3
rails 5.2.6
OS:Linux(CentOS)
IDE:Cloud9
実装
enumとは?
「列挙型」という、整数が割り当てられた文字列を順に出力していく変数のことで、0を男性、1を女性のように、整数の値に何かしらの意味づけを行ってデータを管理することができます。「hashのkey部分の定数を保存すると、そのkeyに対応するvalueの整数が保存される仕組み」とのこと(【Rails】 enumチュートリアルより)
今回は、以下のような値で進めていくことにします。
{ 0: outstanding(未対応), 1: in_progress(対応中), 2: closed(対応済)}
STEP1. enumの定義
👇 FormInquiryモデルのresponse_status
カラムに対して、enumを定義します
belongs_to :user
enum response_status: { outstanding: 0, in_progress: 1, closed: 2 }
次に、enumを日本語化します。
👇 Gemfileにenum_help
を追記して、保存したらbundle install
します。
gem 'enum_help'
👇 英語名に対応する日本語の値を、ja.yml
に定義します。
ja:
time:
formats:
default: "%Y/%m/%d %H:%M"
enums:
form_inquiry:
response_status:
outstanding: "未対応"
in_progress: "対応中"
closed: "対応済"
👇 もしアプリケーションのデフォルト言語が日本語になっていない場合は、設定しておきます
module App
class Application < Rails::Application
# 略
config.i18n.default_locale = :ja
end
end
STEP2. コントローラーに記述
対応ステータスの更新はupdateアクションで行います。
更新できたら、問い合わせ詳細画面にリダイレクトし、フラッシュメッセージを表示するようにしています。
class Admin::FormInquiriesController < ApplicationController
before_action :authenticate_admin!
before_action :set_form_inquiry, only: [:show, :update]
def index
@form_inquiries = FormInquiry.all.includes(:user).order(created_at: "DESC").page(params[:page]).per(10)
end
def show
@user = User.find(@form_inquiry.user_id)
end
def update
if @form_inquiry.update(form_inquiry_params)
redirect_to admin_form_inquiry_path(@form_inquiry), notice: "対応ステータスを更新しました"
else
render :show, alert: "対応ステータスを更新できませんでした"
end
end
private
def form_inquiry_params
params.require(:form_inquiry).permit(:response_status)
end
def set_form_inquiry
@form_inquiry = FormInquiry.find(params[:id])
end
end
STEP3. ビューの記述
問い合わせ詳細(show)
👇 対応ステータスの更新は、問い合わせ詳細画面で行うため、show.html.erb
にセレクトボックスを実装します(※該当部分のみ抜粋しています)
<%= form_with model: [:admin, @form_inquiry], method: :patch, local: true do |f| %>
<%= f.select :response_status, FormInquiry.response_statuses.keys.map {|k| [I18n.t("enums.form_inquiry.response_status.#{k}"), k]} %>
<%= f.submit "変更" %>
<% end %>
ここでは、enumの値(未対応/対応中/対応済)のセレクトボックスを作成するため、mapメソッド(配列の要素の数だけブロック内で処理を繰り返して、新しい配列を返すメソッド)を使用します。
ここで何をしているか確認しておくと、
- keysメソッドでハッシュオブジェクトからキーのみ配列の形で取り出している(
outstanding
/in_progress
/closed
) - I18nのtranslateメソッド(
I18n.t
)でenumのキーの内容を翻訳している - keysメソッドで取り出した値一つ一つに対しmapメソッドで処理し、二次元配列(配列の中に、配列が格納された形の配列のこと)を戻り値として返す
試しにrails c
で返り値を見てみると、こうなっています👇
[3]はtranslateメソッドを使わなかった場合を一応出力してみた形です。
二次元配列の2つ目の要素(["対応中", "in_progress"]
)を選択して、検証ツールで見てみると、この二次元配列の1つ目の要素がoptionタグの表示部分に、2つ目の要素がvalueに入る仕組みであることがわかります。
これが他2つの二次元配列に対しても展開されて、セレクトボックスが生成されているようですね。
問い合わせ一覧(index)
👇 7〜13行目で、一覧に表示する対応ステータスをif文を使って分岐させています。
日本語化した定数の値を表示したいので、カラム名の末尾に_i18n
を追記します。
<table>
<% @form_inquiries.each do |form_inquiry| %>
<tr>
<td><%= l form_inquiry.created_at %></td>
<td><%= link_to form_inquiry.user.name, admin_user_path(form_inquiry.user.id) %></td>
<td>
<% if form_inquiry.response_status == 'outstanding' %>
<%= form_inquiry.response_status_i18n %>
<% elsif form_inquiry.response_status == 'in_progress' %>
<%= form_inquiry.response_status_i18n %>
<% else %>
<%= form_inquiry.response_status_i18n %>
<% end %>
</td>
<td>
<%= link_to "詳細", admin_form_inquiry_path(form_inquiry.id), class:'btn btn-sm py-0 btn-outline-secondary' %>
</td>
</tr>
<% end %>
</table>
これで対応ステータスが更新できるようになりました!
keysメソッドやmapメソッドの部分は、個人的にまだ理解が難しいのですが、言語化することで理解が少し深まったように思います。何かお気づきの点があれば、ぜひご教示ください。
参考資料
- 【Rails】enumをI18n対応させるenum_helpが便利すぎた
- 【Rails】 enumチュートリアル
- 【Ruby】 mapメソッドの基礎から応用をマスターして、効率的なコードを書けるようにしよう!
- Rubyでハッシュオブジェクトからキーや値を取り出す方法【初心者向け】
- [【初心者向け】i18nを利用して、enumのf.selectオプションを日本語化する[Rails]] (https://azmengineer.hateblo.jp/entry/2019/06/20/101622)