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をご覧いただければと思います。
私は、ここまでで満足!