プライマリキーを使った1:1関連でカラム数の多いテーブルを分割する - Hidden in Plain Sight
プチ・デザインパターン的なやつ、僕もよくやってます。
で、運用エンジニア的にはデータの不整合を起こしうる要因はできる限りDB側の制約でも防ぎたいので、このusersとprofilesの場合だと、usersで自動採番されたidをprofilesでも使うのでprofilesの自動採番する機能は残しておくと事故るリスクがあるので落としたいわけです。
なので、僕はいつもこんな感じでmigrationを書いてます。
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :email, charset: 'ascii', collation: 'ascii_bin', null: false t.string :password_digest, charset: 'ascii', collation: 'ascii_bin' end add_index :users, :email, name: "idx_email", unique: true end end class CreateProfiles < ActiveRecord::Migration def change create_table :profiles, id: false do |t| t.integer :id, null: false t.string :name t.integer :gender, limit: 1 t.datetime :birthday end execute("ALTER TABLE `profiles` ADD PRIMARY KEY (`id`)") end end
usersテーブルの文字セットや照合順序の指定はRails - ActiveRecordでカラム毎にcharsetとcollationを指定する - Qiitaでやってます。
ActiveRecordが作る自動採番されるプライマリキーとは異なる定義を使うとrake db:schema:load
でスキーマが正確に復元できなくなるので
config/application.rb
でスキーマのフォーマットをSQLに変更しています。
config.active_record.schema_format = :sql
db/structure.sql
にこんな感じでダンプされます。
-- (snip) -- -- Table structure for table `profiles` -- DROP TABLE IF EXISTS `profiles`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `profiles` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `gender` tinyint(4) DEFAULT NULL, `birthday` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `schema_migrations` -- DROP TABLE IF EXISTS `schema_migrations`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `schema_migrations` ( `version` varchar(191) NOT NULL, UNIQUE KEY `unique_schema_migrations` (`version`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Table structure for table `users` -- DROP TABLE IF EXISTS `users`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `email` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_digest` varchar(255) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; -- (snip)
これでうっかりミスってprofilesにINSERTして採番されちゃうリスクが軽減されて安心感が増しますね!