notionの各記事につけることのできる絵文字のように、各ユーザーのnicknameにランダムに絵文字を付与させたいと思います。現在nicknameカラムはstring型で、null制約がかかっています。

ランダムにデータを取得する方法について調べてみました。shufflerandなどのメソッドがあったのですが、今回は配列の要素1つをランダムに取得したいので sampleメソッドを使っていこうと思います。

まず最初にUserモデルにユーザーを新規作成する前にset_nicknameメソッドを実行するように設定して行きます。

class User < ApplicationRecord
	before_create :set_nickname

	privete
	
	def set_nickname
    while self.nickname.blank? || User.find_by(nickname: self.nickname).present? do
      self.nickname = ['🐴', '🐣', '🦕', '🐡'].sample
    end
  end
end

これでフォームにnickname以外を入力せずに保存しようとすると、nicknameが空白で登録できないというバリデーションエラーが発生します。

一旦binding.pryでデバックして調べてみることにしました。

users_controller.rb

def create
    @user = User.new(user_params)
    if @user.save
      redirect_to login_path, success: t('.success')
    else
      binding.pry # 失敗する原因を究明するためのbinding.pry
      flash.now[:danger] = t('.fail')
      render :new
    end
end
Started POST "/users" for ::1 at 2021-06-09 14:55:21 +0900
Processing by UsersController#create as HTML
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"nickname"=>"", "name"=>"hanako", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"register"}
  TRANSACTION (1.0ms)  BEGIN
  ↳ app/controllers/users_controller.rb:19:in `create'
  User Exists? (1.0ms)  SELECT 1 AS one FROM `users` WHERE `users`.`name` = 'hanako' LIMIT 1
  ↳ app/controllers/users_controller.rb:19:in `create'
  TRANSACTION (0.8ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:19:in `create'

From: /Users/SAYO/workspace/portfolio/emoji_diary/emoji_diary/app/controllers/users_controller.rb:23 UsersController#create:

    17: def create
    18:   @user = User.new(user_params)
    19:   if @user.save
    20:     redirect_to login_path, success: t('.success')
    21:   else
    22:     binding.pry
 => 23:     flash.now[:danger] = t('.fail')
    24:     render :new
    25:   end
    26: end

[1] pry(#<UsersController>)> @user
=> #<User:0x00007ffb1d5bae08
 id: nil,
 nickname: "",
 name: "hanako",
 crypted_password: "$2a$10$Uv6mDNXav5Dq/wY4.2sZNuL4shZe0Z1FIB9URPkjbzb8g3/QBC9f6",
 salt: "y1rNQVe6MQ2Qn7428RP6",
 created_at: nil,
 updated_at: nil>

想像通り、@userのnicknameカラムが空欄でした。

arrayに配列で並べた絵文字を数個入れました。そして@usernicknamesampleメソッド(配列からランダムに1つデータを取り出してくれる)を使ってデータを入れました。それからsaveをしてみると、保存することができました。実際に新規登録できているか確認するとできているのがわかりました。

[2] pry(#<UsersController>)> array = ['🐴', '🐣', '🦕', '🐡']
=> ["🐴", "🐣", "🦕", "🐡"]
[3] pry(#<UsersController>)> @user.nickname = array.sample
=> "🦕"
[4] pry(#<UsersController>)> @user.save
  TRANSACTION (19.2ms)  BEGIN
  ↳ (pry):6:in `create'
  User Exists? (5.9ms)  SELECT 1 AS one FROM `users` WHERE `users`.`name` = 'hanako' LIMIT 1
  ↳ (pry):6:in `create'
  User Load (47.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`nickname` = '🦕' LIMIT 1
  ↳ app/models/user.rb:73:in `set_nickname'
  User Create (59.1ms)  INSERT INTO `users` (`nickname`, `name`, `crypted_password`, `salt`, `created_at`, `updated_at`) VALUES ('🦕', 'hanako', '$2a$10$u8nSRJDeHaHzIYAMNr5Rvemla4NvsbS.jF598W2K/1LRC5D1tB3ZS', 'MpnA1wV-d4VVsjTRH_Lr', '2021-06-09 05:57:20.850310', '2021-06-09 05:57:20.850310')
  ↳ (pry):6:in `create'
  TRANSACTION (43.5ms)  COMMIT
  ↳ (pry):6:in `create'
=> true
[5] pry(#<UsersController>)> User.last
  User Load (13.7ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
  ↳ (pry):7:in `create'
=> #<User:0x00007ffb1f984050
 id: 12,
 nickname: "🦕",
 name: "hanako",
 crypted_password: "$2a$10$u8nSRJDeHaHzIYAMNr5Rvemla4NvsbS.jF598W2K/1LRC5D1tB3ZS",
 salt: "MpnA1wV-d4VVsjTRH_Lr",
 created_at: Wed, 09 Jun 2021 14:57:20.850310000 JST +09:00,
 updated_at: Wed, 09 Jun 2021 14:57:20.850310000 JST +09:00>

うーん、コンソールでならうまくできるのに、、、。と思ったのでusersコントローラにメソッドを移してみることにしました。

def create
    @user = User.new(user_params)
    @user.nickname = ['🐴', '🐣', '🦕', '🐡'].sample
    if @user.save
      redirect_to login_path, success: t('.success')
    else
      flash.now[:danger] = t('.fail')
      render :new
    end
end