🦓

[Rails]enumを使ってユーザに性別を追加する1/2

2023/06/24に公開

はじめに

作成したRailsアプリに、ユーザのテーブルに性別カラムgenderを追加します。
ユーザー登録時の性別のセレクト部分はenumを使って「その他・男性・女性」が表示され、その際に特に操作が無かれば「その他」が選択されるようにしていきます。

環境

Rails 6.1.4.1
ruby 3.0.2

tl;dr

  1. enumとは
  2. ユーザテーブルにgenderカラムを追加する
  3. enumを宣言する
  4. enum_helpgemを使う
  5. genderをローカライズする
  6. ユーザコントローラーを編集する
  7. ビューにセレクトボックスを追加する

enumとは

enumは、Railsで提供される機能の一つです。enumを使用すると、データベースの列(カラム)に対して、あらかじめ定義された値のセットを関連付けることができます。

具体的には、enumを使用してモデルの属性を定義すると、その属性の値をシンボルで指定できるようになります。これにより、データベース内で整数値として保存される属性に、より意味のある値を関連付けることができます。

以下は、enumの使用例です:

app/models/user.rb
class User < ApplicationRecord
  enum role: [:admin, :user, :guest]
end

上記の例では、Userモデルにrole属性を定義しています。enumメソッドを使ってrole属性を定義し、:admin:user:guestの3つの値を定義しています。

これにより、Userモデルのインスタンスに対して以下のようにアクセスできます:

user = User.new(role: :admin)
user.admin?  # true
user.role    # "admin"

また、enumはデフォルトでいくつかの便利なメソッドも提供しています。たとえば、各値に対応する真偽値のメソッド(admin?user?guest?)や、定義された値の一覧を返すメソッド(User.roles)などです。

enumはデータベースの列に関連付けるだけでなく、モデルのビューなどの表示部分でも利用できます。たとえば、フォームのセレクトボックスに値を表示する際には、User.roles.keysを使って選択肢を取得することができます。

enumを使うことで、整数値だけでなく、意味のある値を使って属性を扱うことができ、コードの可読性と保守性が向上します。
https://railsguides.jp/active_record_querying.html#enum

ユーザテーブルにgenderカラムを追加する

bin/rails generate migration AddGenderToUsers
Running via Spring preloader in process 47375
      invoke  active_record
      create    db/migrate/20230624074517_add_gender_to_users.rb
db/migrate/xxx_add_gender_to_users.rb
class AddGenderToUsers < ActiveRecord::Migration[6.1]
  def change
    add_column :users, :gender, :interger, default: 0
  end
end
bin/rails db:migrate
Running via Spring preloader in process 48507
== 20230624074517 AddGenderToUsers: migrating =================================
-- add_column(:users, :gender, :interger, {:default=>0})
   -> 0.0031s
== 20230624074517 AddGenderToUsers: migrated (0.0032s) ========================

ユーザのgenderがデフォルトになっていることを確認します。

irb(main):005:0> User.first.gender
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 0

enumを宣言する

app/models/user.rb
class User < ApplicationRecord
  enum gender: {other: 0 , male: 1, female: 2}
end

enum_helpgemを使う

enum_helpとはenumで定義した値をi18n化させることができるgemです。

Gemfile
gem 'enum_help'
bundle install

https://github.com/zmbacker/enum_help

genderをローカライズする

config/locales/ja.yml
ja:
  enums:
      user:
        gender:
          other: その他
          male: 男性
          female: 女性

これでenum_helpによるメソッドが使えるようになりました。
翻訳されたことを確認します。

irb(main):001:0> user = User.first
   (0.9ms)  SELECT sqlite_version(*)
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 
#<User:0x00007fe2e351e820
...
irb(main):002:0> user.gender
=> "other"
irb(main):003:0> user.gender_i18n
=> "その他"
irb(main):005:0> User.genders
=> {"other"=>0, "male"=>1, "female"=>2}
irb(main):006:0> User.genders_i18n
=> {"other"=>"その他", "male"=>"男性", "female"=>"女性"}
irb(main):007:0> User.genders_i18n.invert
=> {"その他"=>"other", "男性"=>"male", "女性"=>"female"}
irb(main):08:0> User.genders_i18n.invert.map{|key,value|[key,value]}
=> [["その他", "other"], ["男性", "male"], ["女性", "female"]]
irb(main):09:0> User.genders_i18n.invert.map{|key,value|[key,User.
genders[value]]}
=> [["その他", 0], ["男性", 1], ["女性", 2]]

ユーザコントローラーを編集する

パラメーターにgenderを追加します。
性別セレクト用オプションを作成します。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
    @gender_options = User.genders_i18n.invert.map{|key,value|[key,value]}
  end
  
  private
  
  def user_params
    params.require(:user).permit(:email, :name, :gender, :password, :password_confirmation)
  end
end

app/views/users/new.html.erbを編集する

ユーザーの新規作成フォームに性別のセレクトを追加していきます。

app/views/users/new.html.erb
<div class="mb-3">
     <%= f.label :gender %>
     <%= f.select :gender, @gender_options, { include_blank: '性別を選択してください' }, class: 'form-control' %>
</div>

ユーザを作成し、選択した性別をDBに登録されたことを確認します。
また、何も選択しない場合ではDBに0(その他)を登録されたことを確認します。

終わりに

gemを使わないで実装する方法もあるみたいので、今度そちらも試していきたいと思います。

https://qiita.com/kikikikimorimori/items/353f69e31b42e85b9c29
https://zenn.dev/farstep/articles/b1cebeaefd324b
https://guides.rubyonrails.org/form_helpers.html#making-select-boxes-with-ease

Discussion