【Rails】ユーザー専用の家計簿機能

# 1.概要
この記事では、Ruby on Rails でログイン機能（Deviseなど）を持つWebアプリに、ユーザーごとの家計簿（収支記録）機能を追加する方法を解説します。

### 実装する機能
- ログインユーザーだけが自分の家計簿を見られる
- 月ごとの収入・支出・残高を表示
- 家計簿の追加・編集・削除
- カテゴリの選択（例：食費・給料など）

### 完成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777937/6ee60a12-0ca9-4dc7-9b30-977c7399a0e6.png)

# 2.Calculationモデルを作成
### 記録データ（収入・支出など）を保存するためのモデルです。
```ruby:コマンドプロンプト
rails generate model Calculation date:date amount:integer calculation_type:string note:text category_id:integer user:references
rails db:migrate
```
- `data`: 日付
- `smount`: 金額
- `calculation_type`: 収入/支出
- `note`: メモ
- `category_id`: カテゴリ
- `user_id`: 誰の記録か

# 3.Categoryを準備する（初期データ）
### カテゴリ（食費・交通費など）を一覧から選べるようにします。
```ruby:config/db/seeds.rb
# 自分で変更してね
Category.create([
  { name: "食費" },
  { name: "交通費" },
  { name: "給料" },
  { name: "趣味" },
  { name: "日用品" }
])
```
```ruby:コマンドプロンプト
rails db:seed
```

# 4.モデルの関連付け
### 「1人のユーザーがたくさんの記録を持つ」関係を表現します。
```ruby:models/user.rb
class User < ApplicationRecord

    has_many :calculations, dependent: :destroy # 追加
    
end
```
```ruby:models/calculation.rb
class Calculation < ApplicationRecord

# ここから
    belongs_to :user
    belongs_to :category, optional: true

    validates :date, :amount, :calculation_type, presence: true
# ここまで

end
```

# 5.ルーティング
```ruby:config/routes.rb
resources :calculations
```

# 6.コントローラーを作成
```ruby:コマンドプロンプト
rails generate controller Calculations
```
```ruby:controllers/calculations_controller.rb
class CalculationsController < ApplicationController

# ここから
  before_action :authenticate_user!
  before_action :set_calculation, only: [:edit, :update, :destroy]

  def index
    year = params[:year]&.to_i || Date.today.year
    month = params[:month]&.to_i || Date.today.month
    date = Date.new(year, month, 1)

    @display_year = year
    @display_month = month
    range = date.beginning_of_month..date.end_of_month

    @calculations = current_user.calculations.where(date: range)
    @total_income = @calculations.where(calculation_type: "income").sum(:amount)
    @total_expense = @calculations.where(calculation_type: "expense").sum(:amount)
    @balance = @total_income - @total_expense
  end

  def new
    @calculation = Calculation.new
  end

  def create
    @calculation = current_user.calculations.build(calculation_params)
    if @calculation.save
      redirect_to calculations_path, notice: "登録が完了しました"
    else
      render :new, status: :unprocessable_entity
    end
  end

  def edit; end

  def update
    if @calculation.update(calculation_params)
      redirect_to calculations_path, notice: "更新しました"
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @calculation.destroy
    redirect_to calculations_path, notice: "削除しました"
  end

  private

  def set_calculation
    @calculation = current_user.calculations.find(params[:id])
  end

  def calculation_params
    params.require(:calculation).permit(:date, :amount, :calculation_type, :category_id, :note)
  end
# ここまで

end
```
### `current_user.calculations`とすることで、ログイン中のユーザーだけのデータを取得します。

# 7.ビューを作成
### 一覧表示
```ruby:views/calculations/index.html.erb
<h2><%= @display_year %>年<%= @display_month %>月の家計簿</h2>

<%= form_with url: calculations_path, method: :get, local: true do %>
  年: <%= select_tag :year, options_for_select((2022..2026).to_a, @display_year) %>
  月: <%= select_tag :month, options_for_select((1..12).to_a, @display_month) %>
  <%= submit_tag "表示" %>
<% end %>

<p>収入: <%= @total_income %>円</p>
<p>支出: <%= @total_expense %>円</p>
<p>残高: <%= @balance %>円</p>

<%= link_to "新規作成", new_calculation_path %>

<% if @calculations.any? %>
    <table>
      <thead>
        <tr>
            <th>日付</th>
            <th>金額</th>
            <th>種別</th>
            <th>カテゴリ</th>
            <th>メモ</th>
            <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <% @calculations.order(:date :asc).each do |t| %>
          <tr>
            <td><%= t.date.strftime("%Y-%m-%d") %></td>
            <td><%= t.amount %>円</td>
            <td><%= t.calculation_type == "income" ? "収入" : "支出" %></td>
            <td><%= t.category&.name || "未分類" %></td>
            <td><%= t.note %></td>
            <td>
                <%= link_to "編集", edit_calculation_path(t), class: "btn" %>
                <%= button_to "削除", calculation_path(t), method: :delete, data: { confirm: "本当に削除しますか？" }, class: "btn" %>
            </td>
          </tr>
        <% end %>
      </tbody>
    </table>
<% else %>
  <p>この月には記録がありません。</p>
<% end %>
```
### 新規投稿・編集ページ
```ruby:views/calculations/new.html.erb (edit.html.erbも同様)
<%= form_with model: @calculation, local: true do |f| %>
  <%= f.label :date %>
  <%= f.date_field :date %>

  <%= f.label :amount %>
  <%= f.number_field :amount %>

  <%= f.label :calculation_type %>
  <%= f.select :calculation_type, [["収入", "income"], ["支出", "expense"]] %>

  <%= f.label :category_id, "カテゴリ" %>
  <%= f.collection_select :category_id, Category.all, :id, :name, prompt: "選択してください" %>

  <%= f.label :note %>
  <%= f.text_area :note %>

  <%= f.submit %>
<% end %>
```