【Rails6】ER図とテーブル設計からmodelとmigrateを素早く作成する手順

# はじめに
Qiita初投稿です。
2021年3月から実際の開発案件に参加させて頂き、案件を通じて学んだ内容を投稿したいと思います。
modelやmigrateを作成する情報を多く目にしますが、実際にコードを書いて実装した際、作成手順で迷ったり、migrateの作成し直しを何度も行ったりした点を備忘録的にまとめました。
RubyonRails初学者の為、間違っている情報を記載している場合はご指摘いただけますと幸いです。
 
## 開発環境
- macOS Catalina バージョン 10.15.7
- Ruby 2.7.2
- Rails 6.1.1
- mysql  Ver 8.0.23

## modelとmigrateを作成するまでの流れ
開発において、要件定義やER図・テーブル設計は、より高度な知識や理解を必要とする作業だと思いますが、私の場合は基本設計が既にできあがった状態から参加させて頂きました。
そのため、ここではER図とテーブル設計が完成した状態から、素早く（約半日くらいで）modelとmigrateを作成し、seedsで動作確認を行うまでの流れをまとめたいと思います。
下記のER図とテーブル設計は簡略化したものですが、基本的な項目は網羅するよう記載したつもりです。

## 作業の流れ
1. ER図
2. Userテーブル<br>
　　テーブル情報整理<br>
　　migrateとmodelを作成
3. Productテーブル<br>
　　テーブル情報整理<br>
　　migrateとmodelを作成
4. Contractテーブル<br>
　　テーブル情報整理<br>
　　migrateとmodelを作成
5. seedsでDBテストデータ作成
6. バリデーションが正しく機能するかテストする
7. 正しく関連付け（アソシエーション）ができているかをテストする
8. 補足

# 1. ER図 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228606/ce50f77d-c66e-b219-5ef7-7ab10351cc55.png)
※IE記法

ER図から、モデルの関係性とKeyの指定を把握

 - UserモデルとContractモデルは、１対０以上（1対多）の関係
 - ProductモデルとContractモデルは、１対０以上（1対多）の関係
 - PKやFKについては、テーブル設計と比較して一致確認
 - PK（PRIMARY KEY／主キー）
 - UK（UNIQUE KEY／ユニーク制約キー）
 - FK（FOREIGN KEY／外部キー）

# 2. Userテーブル
|カラム    |カラムの説明  |キー |index|not null|カラムの型|default|備考|
|:-      |:-         |:-: |:-:|:-:|:-:    |:-:|:-:|
|id      |id         |PK  |●  |●  |bigint|   |   |
|name    |ユーザー名   |　  |⚪  |⚪ |string |   |　　　|
|email   |Eメール      |UK |●  |⚪  |string|   |文字数を255文字までに制限する<br>Emailアドレスのフォーマットを検証|
|password|パスワード    |    |   |⚪ |string |   |　　　　|
※　PK = Primary Key　UK = Unique Key
※　● 暗黙的に設定　⚪ 明示的に設定する

### 上記Userテーブルの情報整理（テーブル情報をコードに置き換えて整理）

| |migrate|model|
|:-      |:-         |:- |
|キー【PK】|暗黙的にindex,not null設定が入る||
|キー【UK】 |index: { unique: true }  <br> または <br> add_index :users, :email, unique: true を書く　|uniqueness: true |
|index | index: true を設定 または add_index を書く （PKは自動設定）||
|not null | null: false （PKとUKは自動設定）  | presence: true |
|カラムの型 | name:string 　email:string　password:string　<br>（PKはbigint型が自動で入る） | |
|備考 　|　|  length: { maximum: 255 } <br> format: { with: VALID_EMAIL_REGEX }  <br>  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.freeze |



一意制約は、アプリ側（model）だけでよいのか、DB側（migrate）もかけるのか迷いましたが、両方にかけるのが正解

参考：Railsチュートリアル６章:「Active Recordはデータベースのレベルでは一意性を保証していないという問題」を参照
参考：[Rails 一意性制約のかけ方](https://note.com/norio1629/n/ne604267e36fd)

### Userテーブルのmodelとmigrate作成
上記で整理した内容を実際にターミナルに入力
`$ rails g model モデル名　カラム名：型`
各カラムが作成されるところまではターミナルに入力し、追加設定はmodel、migrateに直接入力、と分けて作業するのがわかりやすいと思います

```ターミナル
$ rails g model User name:string email:string password:string
Running via Spring preloader in process 78395
      invoke  active_record
      create    db/migrate/2021xxxxxxxxxx_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
```
modelとmigrateが作成される（テストはRSpecで書くのであれば、削除）

```ruby:model/user.rb
class User < ApplicationRecord
end
```

```ruby:migrate/2021xxxxxxxxxx_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :password

      t.timestamps
    end
  end
end
```
### テーブル条件をDB側（migrate）に追加する

 - `null: false`
 - `add_index :users, :email, unique: true`

※一意制約は`index: { unique: true }`でもOK
あとで`schema.rb`と見比べたりするのであれば、`add_index:`に`unique: true`としたほうが見やすい

```ruby:migrate/2021xxxxxxxxxx_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name,     null: false
      t.string :email,    null: false
      t.string :password, null: false

      t.timestamps
    end

    add_index :users, :name
    add_index :users, :email, unique: true
  end
end
```

設定し忘れがないか`schema.rb`を確認

```ターミナル
$ rails db:migrate
```

```ruby:db/schema.rb
ActiveRecord::Schema.define(version: 2021_05_xx_xxxxxx) do

  create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", null: false
    t.string "password", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["name"], name: "index_users_on_name"
  end

end

```
### テーブル条件をmodelに追加する

- `presence: true`
- `uniqueness: true`

```ruby:model/user.rb
class User < ApplicationRecord
  validates :name,     presence: true
  validates :email,    presence: true, uniqueness: true
  validates :password, presence: true
end
```

- Emailの255文字制限を追加　`length: { maximum: 255 }`
- 正規表現を定数に代入　`VALID_EMAIL_REGEX = /\A[\w+-.]+@[a-z\d-]+(.[a-z\d-]+)*.[a-z]+\z/i.freeze`
- フォーマット検証を追加 `format: { with: VALID_EMAIL_REGEX }`

```ruby:models/user.rb
class User < ApplicationRecord
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.freeze
  validates :name,     presence: true
  validates :email,    presence: true, uniqueness: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
  validates :password, presence: true
end
```
### 関連付け（アソシエーション）を追加
UserとContractは１：０以上（１：多）なので、`has_many :contract, dependent: :destroy`を追加しておく
※`dependent: :destroy`はUserを削除した時、関連付けしている契約（Contract）も同時に削除する

```ruby:models/user.rb
class User < ApplicationRecord
  has_many :contracts, dependent: :destroy

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.freeze
  validates :name,     presence: true
  validates :email,    presence: true, uniqueness: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
  validates :password, presence: true
end
```
ここで、Userのmigrate、modelをすぐにテストする場合は、[5. seedsでDBテストデータ作成](#5-seedsでdbテストデータ作成)を参考にテストデータを作成してください<br>（この状態ではアソシエイトは動きません）

# 3. Productテーブル

|カラム|カラムの説明|キー|index|not null|カラムの型|default|備考|
|:-  |:-       |:-:|:-:  |:-:     |:-:     |:-:    |:-:|
|id|id|PK|●|●|bigint |       |   |
|product_name|商品名   　　　|　  |⚪  |⚪       |string |      |　　　|
|product_price|商品の価格    | 　　|  |⚪       |integer|0     |     |

※　PK = Primary Key
※　● 暗黙的に設定　⚪ 明示的に設定する

###上記Productテーブルの情報整理（テーブル情報をコードに置き換えて整理）

| |migrate|model|
|:-      |:-         |:- |:-:|:-:|:-:    |:-:|:-:|
|キー【PK】|暗黙的にindex,not null設定が入る|||
|index | add_index を設定 または　index: true を書く （PKは自動設定）||
|not null | null: false （PKは自動設定）  | presence: true ||
|カラムの型 | product_name:string 　product_price:integer　<br>（PKはbigint型が自動で入る） | ||
|default| default: 0 ||

###Productテーブルのmodelとmigrate作成
上記で整理した内容を実際にターミナルに入力
Productテーブル情報を`$ rails g model モデル名　カラム名：型`にあてはめる

```
 $ rails g model Product product_name:string product_price:integer
Running via Spring preloader in process 85812
      invoke  active_record
      create    db/migrate/2021xxxxxxxxxx_create_products.rb
      create    app/models/product.rb
      invoke    test_unit
      create      test/models/product_test.rb
      create      test/fixtures/products.yml
```
```ruby:models/product.rb
class Product < ApplicationRecord
end
```

```ruby:db/migrate/2021xxxxxxxxxx_create_products.rb
class CreateProducts < ActiveRecord::Migration[6.1]
  def change
    create_table :products do |t|
      t.string :product_name
      t.integer :product_price

      t.timestamps
    end
  end
end
```

### テーブル条件をDB側（migrate）に追加する
- `null: false`
- `default: 0`
- `add_index :products, :product_name`

```ruby:migrate/2021xxxxxxxxxx_create_products.rb
class CreateProducts < ActiveRecord::Migration[6.1]
  def change
    create_table :products do |t|
      t.string  :product_name,  null: false
      t.integer :product_price, null: false, default: 0

      t.timestamps
    end

    add_index :products, :product_name
  end
end
```

設定し忘れがないか`schema.rb`を確認

```
$ rails db:migrate
```
```ruby:db/schema.rb
ActiveRecord::Schema.define(version: 2021_05_xx_xxxxxx) do

  create_table "products", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "product_name", null: false
    t.integer "product_price", default: 0, null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["product_name"], name: "index_products_on_product_name"
  end

  create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", null: false
    t.string "password", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["name"], name: "index_users_on_name"
  end

end
```

### テーブル条件をmodelに追加する

-  `presence: true`

```ruby:models/product.rb
class Product < ApplicationRecord
  validates :product_name,  presence: true
  validates :product_price, presence: true
end
```
### 関連付け（アソシエーション）を追加
ProductとContractは１：０以上（１：多）なので、`has_many :contract`を追加しておく
商品（Product）を削除した時に契約（Contract）を同時に削除する必要はないので、`dependent: :destroy`は不要

```ruby:models/product.rb
class Product < ApplicationRecord
  has_many :contracts

  validates :product_name,  presence: true
  validates :product_price, presence: true
end
```

ここで、Productのmigrate、modelをすぐにテストする場合は、[5. seedsでDBテストデータ作成](#5-seedsでdbテストデータ作成)を参考にテストデータを作成してください<br>（この状態ではアソシエイトは動きません）

# 4. Contractテーブル

|カラム           |カラムの説明  |キー|index|not null|カラムの型|default|備考|
|:-             |:-         |:-:|:-:|:-:|:-:|:-:|:-:|
|id             |id         |PK |●  |●|bigint|   |   |
|user_id        |ユーザーID   |FK |●  |●|bigint|   |外部キー（Userテーブルのidと紐付ける）|
|product_id     |商品ID      |FK |●  |●|bigint|   |外部キー（Productテーブルのidと紐付ける）|
|product_name   |商品名      |   |⚪  |⚪|string|   |*Contract作成時、product_nameから転記|
|contract_money |契約金      |   |   |⚪|integer|  0|   |
|contract_status|契約ステータス|   |   |  |integer|   |enum(reservation:0, confirm:1）|
※　PK = Primary Key　FK = Foreign Key
※　● 暗黙的に設定　⚪ 明示的に設定する

###上記Contractテーブルの情報整理（テーブル情報をコードに置き換えて整理）

| |migrate|model|
|:-      |:-         |:- |:-:|:-:|:-:    |:-:|:-:|
|キー【PK】|暗黙的にindex,not null設定が入る|||
|キー【FK】|user:references product:references （暗黙的にindex,not null設定が入る） <br>詳細には、references とすると自動的に null: false と foreign_key: true が migrate に追記される　<br> index: true は記載されないが、index設定が自動的に db/schema.rb に入る||
|index | add_index :contracts, :product_name を設定 または　index: true を書く （PK,FKは自動設定）||
|not null | references で null: false 設定  | presence: true を設定 ||
|カラムの型 | product_name:string 　contract_money:integer　contract_status:integer　<br>（PKはbigint型が自動で入る） | ||
|default| default: 0 |             |
|備考|                |enum contract_status: { reservation: 0, confirm: 1, }|

###Contractテーブルのmodelとmigrate作成
上記で整理した内容を実際にターミナルに入力
Contractテーブル情報を`$ rails g model モデル名　カラム名：型`にあてはめる

```ターミナル
$ rails g model Contract user:references product:references product_name:string contract_money:integer contract_status:integer
Running via Spring preloader in process 79699
      invoke  active_record
      create    db/migrate/2021xxxxxxxxxx_create_contracts.rb
      create    app/models/contract.rb
      invoke    test_unit
      create      test/models/contract_test.rb
      create      test/fixtures/contracts.yml
```
modelとmigrateが作成される（テストはRSpecで書くなら、削除）

```ruby:model/contract.rb
class Contract < ApplicationRecord
  belongs_to :user
  belongs_to :product
end
```
```ruby:migrate/2021xxxxxxxxxx_create_contracts.rb
class CreateContracts < ActiveRecord::Migration[6.1]
  def change
    create_table :contracts do |t|
      t.references :user, null: false, foreign_key: true
      t.references :product, null: false, foreign_key: true
      t.string :product_name
      t.integer :contract_money
      t.integer :contract_status

      t.timestamps
    end
  end
end
```
### テーブル条件をDB側（migrate）に追加
- index　`add_index :contracts, :product_name`
- not null設定　`null: false`
- default設定　`default: 0`

ついでに行も揃えると見やすい

```ruby:migrate/2021xxxxxxxxxx_create_contracts.rb
class CreateContracts < ActiveRecord::Migration[6.1]
  def change
    create_table :contracts do |t|
      t.references :user,           null: false, foreign_key: true
      t.references :product,        null: false, foreign_key: true
      t.string     :product_name,   null: false
      t.integer    :contract_money, null: false, default: 0
      t.integer    :contract_status

      t.timestamps
    end

    add_index :contracts, :product_name
  end
end
```
設定漏れがないか`schema.rb`を確認

```ターミナル
$ rails db:migrate
```

```ruby:db/schema.rb
ActiveRecord::Schema.define(version: 2021_05_26_081531) do

  create_table "contracts", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.bigint "user_id", null: false
    t.bigint "product_id", null: false
    t.string "product_name", null: false
    t.integer "contract_money", default: 0, null: false
    t.integer "contract_status"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["product_id"], name: "index_contracts_on_product_id"
    t.index ["product_name"], name: "index_contracts_on_product_name"
    t.index ["user_id"], name: "index_contracts_on_user_id"
  end

  create_table "products", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "product_name", null: false
    t.integer "product_price", default: 0, null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["product_name"], name: "index_products_on_product_name"
  end

  create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "name", null: false
    t.string "email", null: false
    t.string "password", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["name"], name: "index_users_on_name"
  end

  add_foreign_key "contracts", "products"
  add_foreign_key "contracts", "users"
end

```
今回のテーブル設計にはありませんが、以下はよくある？設定
　`t.references :user`の参照先テーブル名がカラム名とは違う場合　`foreign_key: { to_table: :customers }`と参照先を指定する

```ruby:migrate/2021xxxxxxxxxx_create_contracts.rb
t.references :user, null: false, foreign_key: { to_table: :customers }
```



### テーブル条件をmodelに追加
- `presence: true` 追加
- `enum`追加

```ruby:model/contract.rb
class Contract < ApplicationRecord
  belongs_to :user
  belongs_to :product

  validates :user,            presence: true
  validates :product,         presence: true
  validates :product_name,    presence: true
  validates :contract_money,  presence: true
  validates :contract_status, presence: true

  enum contract_status: {
    reservation: 0,
    confirm: 1,
  }
end
```
### 関連付け（アソシエーション）を追加
UserモデルとContractモデルの「１対０以上（1対多）」の関係と、ProductモデルとContractモデルの、「１対０以上（1対多）」の関係をmodelに反映

```ruby:model/contract.rb
class Contract < ApplicationRecord
  belongs_to :user
  belongs_to :product
  
  validates :user,            presence: true
  validates :product,         presence: true
  validates :product_name,    presence: true
  validates :contract_money,  presence: true
  validates :contract_status, presence: true

  enum contract_status: {
    reservation: 0,
    confirm: 1,
  }
end
```

```ruby:models/user.rb
class User < ApplicationRecord
  has_many :contracts, dependent: :destroy

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.freeze
  validates :name,     presence: true
  validates :email,    presence: true, uniqueness: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
  validates :password, presence: true
end
```

```ruby:model/product.rb
class Product < ApplicationRecord
  has_many :contracts

  validates :product_name,  presence: true
  validates :product_price, presence: true
end
```
これで、関連付けされた別テーブルのデータが使用できるようになるので、次項以下で確認します
migrateとmodelの作成作業はひとまず完了です

# 5. seedsでDBテストデータ作成
`db/seeds.rb`でテストデータを作成する目的は、以下二点です
①DBが正常に保存できるかを確認する
②テーブル設計どおりにモデルのバリデーション等が機能するか確認する

```ruby:db/seeds.rb
user1 = User.create!(name: "akagi", email: "akagi@example.com", password: "password")
user2 = User.create!(name: "uozumi", email: "uozumi@example.com", password: "password")
user3 = User.create!(name: "anzai", email: "anzai@example.com", password: "password")

puts "userデータの投入に成功しました！"

product1 = Product.create!(product_name: "サッカーボール", product_price: 10000 )
product2 = Product.create!(product_name: "バスケットボール", product_price: 15000)

puts "productデータの投入に成功しました！"

Contract.create!(user_id: user1.id, product_id: product1.id, product_name: product1.product_name, contract_money: 500000, contract_status: 0)
Contract.create!(user_id: user2.id, product_id: product2.id, product_name: product2.product_name, contract_money: 1000000, contract_status: 1)
Contract.create!(user_id: user1.id, product_id: product2.id, product_name: product2.product_name, contract_money: 500000, contract_status: 0)

puts "Contractデータの投入に成功しました！"
```
テストデータを作成するコマンドを入力

```
$ rails db:seed
```
※一度、seedデータを作成し終えている場合は、`$ rails db:reset`を実行

うまく保存できない（エラーが出る）場合は、`binding.pry`を`seeds.rb`に入れてどこがうまく行かないのか確認しながら修正する


# 6. バリデーションが正しく機能するかテストする
全てのバリデーションテストはRSpecのモデルスペックで実装することを想定し、ここでは、主な項目だけをテストしていきます。

```ruby:ターミナル
$ rails console

# user4を正常なデータとして作成することができる（seeds.rbが動作する時点で確認済ですが…）
> user4 = User.create(name: "mitui", email: "mitui@example.com", password: "password")

# Emailの正規表現が機能しているか確認
> user4.update(email: "mitui@..example.com")
=> false

# エラーメッセージも確認する
> user4.errors.full_messages
=> ["Email is invalid"]

# 文字制限が機能している確認
> user4.update(email:" #{"m" * 255}@example.com")
=> false
> user4.errors.full_messages
=> ["Email is too long (maximum is 255 characters)", "Email is invalid"]

# uniqueが機能しているか確認
> user4.update(email: "akagi@example.com")
=> false
> user4.errors.full_messages
=> ["Email has already been taken"]
```


# 7. 正しく関連付け（association）ができているかをテストする


```ruby:ターミナル
$ rails console

# Userが正常に保存されているか確認
> user1, user2, user3 = User.all

> user1.name
=> "akagi"

# Userモデルの has_many :contracts, dependent: :destroy が関連付けできているか確認
> user1.contracts


# user1のcontractsを全て取得する
> user1.contracts.all

# user1のcontractsの１つ目のproduct_nameを取得する
> user1.contracts[0].product_name

# productモデルの has_many :contracts が関連付けできているか確認
> product2 = Product.second

# productオブジェクトから、contractと関連付けされたuserを取得する
> product2.contracts[1].user

# user3.contracts.create!でuser3とproduct2のContractのインスタンスを作成して保存
> user3.contracts.create!(product_id: product2.id, product_name: product2.product_name, contract_money: 750000, contract_status: 0)

# 作成保存できているか、Contractを確認
> Contract.last
```

これで、DB周辺のmodelとmigrateの確認も完了
あとは必要な機能要件に合わせて、viewsとcontrollersの作成に入る

参考：[Railsガイド Active Record](https://railsguides.jp/association_basics.html)


# 8. 補足
途中でカラムを追加したくなった時の手順で迷ったので補足
例えば、db/migrate/2021xxxxxxxxxx_create_contracts.rbに `contract_title`をうっかり作成し忘れていた事に途中で気づいたような時、AddColumnを多用するのはよくない（自論）と思いますので、githubのmasterにマージする前後で作業を分けました
### githubにブランチをpushしてmasterにマージする前

```ruby:ターミナル
# どこまで戻すか確認する
$ rails db:migrate:status

database: qiita_posting

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20210526055004  Create products
   up     20210526065824  Create users
   up     20210526081531  Create contracts

# 必要なところまでdbを戻す（以下は一つだけ戻す書き方）
$ rails db:rollback

# もし、２つ戻すなら、rails db:rollback STEP=2　と書く
```
db/migrateにカラム（contract_title）を追加する

```ruby:db/migrate/2021xxxxxxxxxx_create_contracts.rb
class CreateContracts < ActiveRecord::Migration[6.1]
  def change
    create_table :contracts do |t|
      t.references :user,        null: false, foreign_key: true
      t.references :product,     null: false, foreign_key: true
      t.string :product_name,    null: false
      t.string :contract_title,  null: false
      t.integer :contract_money, null: false, default: 0
      t.integer :contract_status

      t.timestamps
    end

    add_index :contracts, :product_name
  end
end
```

`rails db:migrate`を再度実行する

### githubにブランチをpushしてmasterにマージした後のカラム追加

```
$ rails g migration AddColumnToContracts contract_title:string
```

```ruby:
# 変更内容
  def change
    add_column :contracts, :contract_title, :string, null: false
  end
end
```
参考：[【Rails】 マイグレーションファイルを徹底解説！](https://pikawaka.com/rails/migration)

数ある追加・修正パターンの一部ではありますが、備忘録的にまとめてみました。
私にとっては貴重な初案件であり、参加の機会をくださった方々、また技術不足の私にspatial.chatやzoom、Slackでサポート頂いた開発メンバーの方々に、この場を借りて厚く御礼申し上げます。
また、記載している内容の間違いやよりよい手順等ありましたら、ご指摘頂けますと幸いです。