LoginSignup
35
28

More than 3 years have passed since last update.

【Rails】URLでidの代わりにランダムな文字列を表示させる

Last updated at Posted at 2019-02-21

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.
今回はこちらを使ってみます。

Gemfile
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をはりました。

/db/migrate/YYYYMMDDhhmmss_create_users.rb
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をはります。

/db/migrate/YYYYMMDDhhmmss_add_column_public_uid_to_users.rb
class AddColumnPublicUidToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :public_uid, :string
    add_index  :users, :public_uid, unique: true
  end
end

マイグレーションを適用します。
bash
$ rails db:migrate

3. Userモデルにpublic_uidを自動生成するコードを付与

対象のモデルファイルにgenerate_public_uidというコードを1行追加するだけです。これによってモデルがDBに登録されるタイミングで自動的にpublic_uidに8桁のランダムな文字列が付与されるようになります。

/app/models/user.rb
class User < ApplicationRecord
  generate_public_uid
end

4. to_paramメソッドをオーバーライド

to_paramメソッドを使ってURLの:id:public_uidに変更します。

/app/models/user.rb
class User < ApplicationRecord
  generate_public_uid

  def to_param
    public_uid
  end
end

5. コントローラ側でpublic_uidで検索

scaffoldでモデルを作成すると、コントローラファイルで以下のようにモデル検索がなされていると思います。

/app/controllers/users_controller.rb
private
  def set_user
    @user = User.find(params[:id])
  end

to_paramをオーバーライドしたため、params[:id]にはpublic_uidの値が入るようになっており、findメソッドでは該当のidを持つUserモデルのレコードが存在しないためエラーになってしまいます。
そこで、以下のように編集してpublic_uidでUserモデルを検索するように変更します。

/app/controllers/users_controller.rb
private
  def set_user
    @user = User.find_by(public_uid: params[:id])
  end

以上で、URLにidの代わりにランダムな文字列を表示させることができます。

おまけ

おまけ 1:ランダムな文字列でなくランダムな数字にしたい

public_uid gemでは、ランダムな数字を生成する仕組みとして、NumberRandomNumberSecureRandomという設定を用意してくれています。設定の方法は3で記載したgenerate_public_uidgeneratorを指定してあげるだけです。

/app/models/user.rb
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文字を生成したい場合は以下の通りです。

/app/models/user.rb
class User < ApplicationRecord
  generate_public_uid generator: PublicUid::Generators::HexStringSecureRandom.new(20)
end

Conclusion

便利。
他にも、全くランダムな文字列(a-z,A-Z,0-9)にする方法や、そもそもidをランダム値にする方法などもあるみたいです。詳しくはgemのREADMEをご覧いただければと思います。
私は、ここまでで満足!

Reference

35
28
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
28