Update
gemを使わずに自分で実装する方法を記事におこしました。 --> 【Rails】ランダムな文字列をPrimary keyとして使う - Qiita
Introduction
Railsのscaffoldを使うと、デフォルトで/users/:id/のようにidを使ったURLが生成されます。
しかしながら、システムでシーケンシャルに払い出していて主キーとして使っているidをURLというユーザーが見えるところで使うのって少し抵抗ありません?
ということでURLにはidではなくランダムな文字列(Qiitaの記事はそうなってますね)が表示されるようにする方法をメモります。
Environment
- Rails 5.2.2
- Ruby 2.6.3
1. public_uid gemをインストール
便利そうなgemを作っている方がいらっしゃいました。データをDBに登録するときに、ランダムな文字列を生成してくれるgemです。デフォルトだとHexString(16進数)で生成されます。
GitHub - equivalent/public_uid: Automatically generates random unique public id for record.
今回はこちらを使ってみます。
gem 'public_uid'
$ bundle install
今回は、Userモデルをつくろうとしている前提で物語を進めていきます。
2. public_uidカラムを追加
対象のモデルにpublic_uidカラムを追加していきます。
2-1. Userモデルをこれから作る場合
$ rails g scaffold User name:string public_uid:string
でscaffoldが作成されます。この中にマイグレーションファイルも含まれますが、public_uidは検索対象のカラムになるので検索速度をあげるためにindexをはりました。
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false
t.string :public_uid, null: false
t.timestamps null: false
end
add_index :users, :public_uid, unique: true
end
end
マイグレーションを適用します。
$ rails db:migrate
2-2. Userモデルがすでに存在する場合
$ rails g migration AddColumnPublicUidToUsers public_uid:string
マイグレーションファイルに検索性能をあげるためにpublic_uidへのindexをはります。
class AddColumnPublicUidToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :public_uid, :string
add_index :users, :public_uid, unique: true
end
end
マイグレーションを適用します。
$ rails db:migrate
3. Userモデルにpublic_uidを自動生成するコードを付与
対象のモデルファイルにgenerate_public_uidというコードを1行追加するだけです。これによってモデルがDBに登録されるタイミングで自動的にpublic_uidに8桁のランダムな文字列が付与されるようになります。
class User < ApplicationRecord
generate_public_uid
end
4. to_paramメソッドをオーバーライド
to_paramメソッドを使ってURLの:idを:public_uidに変更します。
class User < ApplicationRecord
generate_public_uid
def to_param
public_uid
end
end
5. コントローラ側でpublic_uidで検索
scaffoldでモデルを作成すると、コントローラファイルで以下のようにモデル検索がなされていると思います。
private
def set_user
@user = User.find(params[:id])
end
to_paramをオーバーライドしたため、params[:id]にはpublic_uidの値が入るようになっており、findメソッドでは該当のidを持つUserモデルのレコードが存在しないためエラーになってしまいます。
そこで、以下のように編集してpublic_uidでUserモデルを検索するように変更します。
private
def set_user
@user = User.find_by(public_uid: params[:id])
end
以上で、URLにidの代わりにランダムな文字列を表示させることができます。
おまけ
おまけ 1:ランダムな文字列でなくランダムな数字にしたい
public_uid gemでは、ランダムな数字を生成する仕組みとして、NumberRandomとNumberSecureRandomという設定を用意してくれています。設定の方法は3で記載したgenerate_public_uidにgeneratorを指定してあげるだけです。
class User < ApplicationRecord
# NumberRandomの場合
generate_public_uid generator: PublicUid::Generators::NumberRandom.new
# Number SecureRandomの場合
generate_public_uid generator: PublicUid::Generators::NumberSecureRandom.new
end
おまけ 2:public_uidの文字数を指定したい
8文字だとすぐ枯渇しかねないモデルの場合はpublic_uidの文字数を増やしたくなります。この場合も、generatorで指定してあげるだけです。例えば20文字を生成したい場合は以下の通りです。
class User < ApplicationRecord
generate_public_uid generator: PublicUid::Generators::HexStringSecureRandom.new(20)
end
Conclusion
便利。
他にも、全くランダムな文字列(a-z,A-Z,0-9)にする方法や、そもそもidをランダム値にする方法などもあるみたいです。詳しくはgemのREADMEをご覧いただければと思います。
私は、ここまでで満足!