【Rails】MVCモデルについて

MVCモデルについて学習した内容をアウトプットとしてまとめてみました。
同じように学習されている方の参考になれば幸いです。

## 目次
1. MVCとは何か
2. なぜMVCが必要なのか
3. それぞれの役割
4. 実際の処理フロー

## 1. MVCとは何か

MVCは以下の3つのコンポーネントの頭文字をとったものです：

- **Model**（モデル）：データベースやビジネスロジックの管理をする
- **View**（ビュー）：データの表示をする
- **Controller**（コントローラー）：ユーザーの入力を受け付け、ModelとViewの橋渡しをする


## 2. なぜMVCが必要なのか

### 2.1 MVCがない場合の問題

以下は、すべての処理を1つのファイルに書いた例です：

```ruby
# 悪い例：すべての処理が混在している
def show_product
  # データベース処理
  product = database.query("SELECT * FROM products WHERE id = 1")
  
  # 価格の計算処理
  tax_included_price = product.price * 1.1
  
  # HTML生成と表示処理
  html = "<div class='product'>"
  html += "<h1>#{product.name}</h1>"
  html += "<p>価格：#{tax_included_price}円（税込）</p>"
  html += "</div>"
  
  render(html)
end
```

**問題点**
- コード量が多く読みづらくなる
- 機能の追加や変更が難しくなる
- コードの再利用が困難
- テストが書きにくい
- チーム開発で混乱が生じやすい

### 2.2 MVCがある場合

同じ機能をMVCで分割すると：

```ruby
# Model: 商品情報の管理
class Product < ApplicationRecord
  # 税込価格の計算
  def price_with_tax
    (price * 1.1).floor
  end
  
  # 在庫があるかチェック
  def in_stock?
    stock > 0
  end
end

# Controller: 商品表示の制御
class ProductsController < ApplicationController
  def show
    # 商品データを取得
    @product = Product.find(params[:id])
  end
end

# View: 商品情報の表示
# show.html.erb
<div class="product">
  <h1><%= @product.name %></h1>
  <p>価格：<%= @product.price_with_tax %>円（税込）</p>
  
  <% if @product.in_stock? %>
    <%= button_to "購入する", buy_product_path(@product) %>
  <% else %>
    <p>在庫切れです</p>
  <% end %>
</div>
```

**MVCのメリット：**
- 役割分担ができる
- コードが整理され、読みやすくなる
- 変更や機能追加が行いやすくなる
- テストが書きやすくなる
- チーム開発が効率的になる

## 3. それぞれの役割

### 3.1 Model（モデル）
- DBとのやりとり
    - テーブル間の関連定義（has_many, belongs_toなど）
    - データの作成、読み取り、更新、削除
- バリデーション
    - データの整合性チェック
- ビジネスロジック
    - データに関する処理や計算
    - 状態管理

```ruby
# 商品モデルの例
class Product < ApplicationRecord
  # 商品名、価格、在庫数は必須入力
  validates :name, :price, :stock, presence: true
  
  # 税込価格の計算
  def price_with_tax
    (price * 1.1).floor
  end
  
  # 在庫があるかチェック
  def in_stock?
    stock > 0
  end
  
  # 購入処理
  def purchase
    return false if stock == 0
    update(stock: stock - 1)
  end
end
```

### 3.2 View（ビュー）
- ユーザーに情報を表示する
- コントローラーから受け取った情報も表示することも可能

```html
# 商品一覧画面の例（index.html.erb）
<h1>商品一覧</h1>

<div class="products">
  <% @products.each do |product| %>
    <div class="product">
      <h2><%= product.name %></h2>
      <p>価格：<%= product.price_with_tax %>円（税込）</p>
      
      <% if product.in_stock? %>
        <%= button_to "購入する", buy_product_path(product) %>
      <% else %>
        <p>在庫切れです</p>
      <% end %>
    </div>
  <% end %>
</div>
```

### 3.3 Controller（コントローラー）
- ユーザーからのリクエストを受け取る
- 必要に応じてモデルにDB操作を依頼する
- 受け取ったデータをビューに渡す
- どのビューを使うか（または、どこにリダイレクトするか）を決める

```ruby
class ProductsController < ApplicationController
  # 商品一覧表示
  def index
    @products = Product.all
  end

  # 商品詳細表示
  def show
    @product = Product.find(params[:id])
  end

  # 商品購入処理
  def buy
    @product = Product.find(params[:id])
    
    if @product.purchase
      redirect_to complete_product_path, notice: '購入が完了しました'
    else
      redirect_to @product, alert: '在庫切れです'
    end
  end
end
```

## 4. 実際の処理フロー

ECサイトを例にしたMVCの処理フローです。

```mermaid
sequenceDiagram
    ユーザー->>+View: 商品を選択して購入ボタンをクリック
    View->>+Controller: 購入情報を送信
    Controller->>+Model: 購入情報の登録を指示
    Model->>-Controller: 登録処理の結果を返却
    Controller->>+View: 購入完了画面の表示を指示
    View->>-ユーザー: 購入完了画面を表示
```
## 
最後まで読んでいただきありがとうございました！

## 参考
https://pikawaka.com/rails/mvc

https://system-kaihatu.com/archives/3204