1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

コード譜投稿アプリを作る#6 (railsのプライマリキーをuuidに変更)

Posted at

← 前回の記事

今回やること

これまでプライマリキーは特にいじらなかったので、idは整数型のオートインクリメント(1, 2, 3 ...)になっています。
これから作る予定のサイトはユーザー投稿型のサイトにしたいので、idをuuidにして/scores/1のようなURLではなく/scores/7a670050-7d74-473c-b322-0322b622b232のようなURLでコード譜それぞれにアクセスできるようにします。

こうすることによるメリットは、

  • URLが推定できてしまうのを防ぐ
  • 全体のレコード数が把握できてしまうのを防ぐ

などがあると思います。
特にサービス立ち上げ当初は「ひとけ」がないのがバレやすいのもあるかなと。

トランザクションがめちゃくちゃ増えそうなサービス内容でもないですし、PostgreSQLであればuuidを採用してもパフォーマンスがめちゃくちゃ落ちるということもなさそうなので、今回は全面的にuuidを採用します。(mysqlだと昇順のuuidを設定しないとかなりパフォーマンスが落ちるらしい)

DBをMySQLからPostgresQLに変更

MySQLでもuuidは使用できるらしいのですが、なんだかめんどくさそうなので簡単に実装できそうなPostgreSQLに乗り換えることにしました。(開発始めたばっかりなので今なら乗り換えも簡単)
今まで特にDBMSの違いについて意識することはなかったんですが、こういう違いもあるんですね…

まずdockerのvolumeを削除します。

$ docker volume ls
    ...
    local    mysql-data
$ docker volume rm mysql-data

docker-compose.ymldatabase.ymlを編集

docker-compose.yml
...
  db:
    image: postgres:9.6
    ports:
      - "5432:5432"
    volumes:
      - pg_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=password
volumes:
  pg_data:
...
config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

buildし直します

$ docker-compose build

Postgresがインストールされていないのでします(ついでにMysql使わないので削除)

Gemfile
gem 'pg'

インストールとDB作成

$ docker-compose run --rm web bundle install
$ docker-compose run --rm web bundle exec rails db:create

これでDBがPostgreSQLに変更できたと思います!

uuidを使用できるようにする

uuidを使用するための拡張機能を有効化します

$ docker-compose run --rm web bundle exec rails g migration enable_extension_for_uuid

以下のようなmigrationファイルが作成されます

class EnableExtensionForUuid < ActiveRecord::Migration[7.0]
  def change
    enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
  end
end

これをmigrateすればuuidは使用できるようになるのですが、前々回作成したScoreテーブルのmigrationファイルも一緒に編集してしまいます。

class CreateScores < ActiveRecord::Migration[7.0]
  def change
   create_table :scores, id: :uuid do |t|
      t.string :title

      t.timestamps
    end
  end
end

id: :uuidという部分でプライマリキーをuuidにするのを指定しています。

ではmigration。

$ docker-compose run --rm web bundle exec rails db:migrate

エラーが出ました。
create_scoresの方のマイグレーションファイルに追記

class CreateScores < ActiveRecord::Migration[7.0]
  def change
    enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
    create_table :scores, id: :uuid do |t|
      t.string :title

      t.timestamps
    end
  end
end

enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')をこちらにも記載。

再度migrationしたところ通りました!

consoleでデータを作成してみます。

irb(main):002:0> Score.create(title: "title")
  TRANSACTION (0.4ms)  BEGIN
  Score Create (6.2ms)  INSERT INTO "scores" ("title", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["title", "title"], ["created_at", "2022-09-19 12:46:38.505748"], ["updated_at", "2022-09-19 12:46:38.505748"]]                                                          
  TRANSACTION (1.6ms)  COMMIT                                    
=>                                                               
#<Score:0x0000aaaaf824fe48                                       
 id: "7a670050-7d74-473c-b322-0322b622b232",                     
 title: "title",                                                 
 created_at: Mon, 19 Sep 2022 12:46:38.505748000 UTC +00:00,     
 updated_at: Mon, 19 Sep 2022 12:46:38.505748000 UTC +00:00>

ちゃんとidがid: "7a670050-7d74-473c-b322-0322b622b232"とuuidになっていますね!

その他便利そうな設定

プライマリキーを自動的にuuidにする

マイグレーションファイルを作成すると自動的にプライマリキーがuuidになるように設定します。
config/initializers/generators.rbファイルを作成。以下のように編集します。

config/initializers/generators.rb
# frozen_string_literal: true

Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

これで新たにマイグレーションファイルをコマンドで作るとid: :uuidが自動的に挿入されます。

first、 lastをいつも通り使えるようにする

ActiveRecordのメソッドにfirstlastがありますが、uuidを使用すると問題が起こります。
firstはidを昇順に並べ、最初のレコードを取ってくるのでランダムに生成されたuuidだとうまく最初のレコードをとってこれません。
Score.order(created_at: :asc).firstというふうに書けば同じことはできるのですが、いちいち書くのはめんどくさいので、application_record.rbを以下のように編集。

/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class
  self.implicit_order_column = "created_at"
end

追記したのはself.implicit_order_column = "created_at"の部分。これでuuidを使う以前と同じようにfirstlastのメソッドが使えます。

記事とか見るとapplication_record.rbではなく個別のモデルにself.implicit_order_column = "created_at"を書いてるのだけど、モデルごとにメソッドの意味が変わると混乱しそうだしここに書いていいんじゃないかなぁと判断。

今日はここまで!

参考にさせていただいたサイト・記事

1
0
0

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?