diff --git a/app/controllers/expenses_controller.rb b/app/controllers/expenses_controller.rb
new file mode 100644
index 0000000..2692f74
--- /dev/null
+++ b/app/controllers/expenses_controller.rb
@@ -0,0 +1,70 @@
+class ExpensesController < ApplicationController
+ before_action :set_expense, only: %i[ show edit update destroy ]
+
+ # GET /expenses or /expenses.json
+ def index
+ @expenses = Expense.all
+ end
+
+ # GET /expenses/1 or /expenses/1.json
+ def show
+ end
+
+ # GET /expenses/new
+ def new
+ @expense = Expense.new
+ end
+
+ # GET /expenses/1/edit
+ def edit
+ end
+
+ # POST /expenses or /expenses.json
+ def create
+ @expense = Expense.new(expense_params)
+
+ respond_to do |format|
+ if @expense.save
+ format.html { redirect_to expense_url(@expense), notice: "Expense was successfully created." }
+ format.json { render :show, status: :created, location: @expense }
+ else
+ format.html { render :new, status: :unprocessable_entity }
+ format.json { render json: @expense.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PATCH/PUT /expenses/1 or /expenses/1.json
+ def update
+ respond_to do |format|
+ if @expense.update(expense_params)
+ format.html { redirect_to expense_url(@expense), notice: "Expense was successfully updated." }
+ format.json { render :show, status: :ok, location: @expense }
+ else
+ format.html { render :edit, status: :unprocessable_entity }
+ format.json { render json: @expense.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /expenses/1 or /expenses/1.json
+ def destroy
+ @expense.destroy!
+
+ respond_to do |format|
+ format.html { redirect_to expenses_url, notice: "Expense was successfully destroyed." }
+ format.json { head :no_content }
+ end
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_expense
+ @expense = Expense.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def expense_params
+ params.require(:expense).permit(:name, :amount, :pricing_type)
+ end
+end
diff --git a/app/helpers/expenses_helper.rb b/app/helpers/expenses_helper.rb
new file mode 100644
index 0000000..1d50062
--- /dev/null
+++ b/app/helpers/expenses_helper.rb
@@ -0,0 +1,2 @@
+module ExpensesHelper
+end
diff --git a/app/models/expense.rb b/app/models/expense.rb
new file mode 100644
index 0000000..15a9560
--- /dev/null
+++ b/app/models/expense.rb
@@ -0,0 +1,2 @@
+class Expense < ApplicationRecord
+end
diff --git a/app/views/expenses/_expense.html.erb b/app/views/expenses/_expense.html.erb
new file mode 100644
index 0000000..6581cb7
--- /dev/null
+++ b/app/views/expenses/_expense.html.erb
@@ -0,0 +1,17 @@
+
+
+ Name:
+ <%= expense.name %>
+
+
+
+ Amount:
+ <%= expense.amount %>
+
+
+
+ Pricing type:
+ <%= expense.pricing_type %>
+
+
+
diff --git a/app/views/expenses/_form.html.erb b/app/views/expenses/_form.html.erb
new file mode 100644
index 0000000..543a3ef
--- /dev/null
+++ b/app/views/expenses/_form.html.erb
@@ -0,0 +1,32 @@
+<%= form_with(model: expense) do |form| %>
+ <% if expense.errors.any? %>
+
+
<%= pluralize(expense.errors.count, "error") %> prohibited this expense from being saved:
+
+
+ <% expense.errors.each do |error| %>
+ - <%= error.full_message %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <%= form.label :name, style: "display: block" %>
+ <%= form.text_field :name %>
+
+
+
+ <%= form.label :amount, style: "display: block" %>
+ <%= form.text_field :amount %>
+
+
+
+ <%= form.label :pricing_type, style: "display: block" %>
+ <%= form.text_field :pricing_type %>
+
+
+
+ <%= form.submit %>
+
+<% end %>
diff --git a/app/views/expenses/edit.html.erb b/app/views/expenses/edit.html.erb
new file mode 100644
index 0000000..75bab6f
--- /dev/null
+++ b/app/views/expenses/edit.html.erb
@@ -0,0 +1,10 @@
+Editing expense
+
+<%= render "form", expense: @expense %>
+
+
+
+
+ <%= link_to "Show this expense", @expense %> |
+ <%= link_to "Back to expenses", expenses_path %>
+
diff --git a/app/views/expenses/index.html.erb b/app/views/expenses/index.html.erb
new file mode 100644
index 0000000..a25f060
--- /dev/null
+++ b/app/views/expenses/index.html.erb
@@ -0,0 +1,14 @@
+<%= notice %>
+
+Expenses
+
+
+ <% @expenses.each do |expense| %>
+ <%= render expense %>
+
+ <%= link_to "Show this expense", expense %>
+
+ <% end %>
+
+
+<%= link_to "New expense", new_expense_path %>
diff --git a/app/views/expenses/new.html.erb b/app/views/expenses/new.html.erb
new file mode 100644
index 0000000..17d6299
--- /dev/null
+++ b/app/views/expenses/new.html.erb
@@ -0,0 +1,9 @@
+New expense
+
+<%= render "form", expense: @expense %>
+
+
+
+
+ <%= link_to "Back to expenses", expenses_path %>
+
diff --git a/app/views/expenses/show.html.erb b/app/views/expenses/show.html.erb
new file mode 100644
index 0000000..2262a0e
--- /dev/null
+++ b/app/views/expenses/show.html.erb
@@ -0,0 +1,10 @@
+<%= notice %>
+
+<%= render @expense %>
+
+
+ <%= link_to "Edit this expense", edit_expense_path(@expense) %> |
+ <%= link_to "Back to expenses", expenses_path %>
+
+ <%= button_to "Destroy this expense", @expense, method: :delete %>
+
diff --git a/config/routes.rb b/config/routes.rb
index a125ef0..8a4ea4a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,4 +1,5 @@
Rails.application.routes.draw do
+ resources :expenses
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
diff --git a/db/migrate/20240711175425_create_expenses.rb b/db/migrate/20240711175425_create_expenses.rb
new file mode 100644
index 0000000..63d0f2b
--- /dev/null
+++ b/db/migrate/20240711175425_create_expenses.rb
@@ -0,0 +1,12 @@
+class CreateExpenses < ActiveRecord::Migration[7.1]
+ def change
+ create_enum :pricing_types, ["fixed", "per_person"]
+ create_table :expenses, id: :uuid do |t|
+ t.string :name
+ t.decimal :amount
+ t.enum :pricing_type, enum_type: :pricing_types, default: "fixed", null: false
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f913998..7774eec 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,8 +10,20 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.1].define(version: 0) do
+ActiveRecord::Schema[7.1].define(version: 2024_07_11_175425) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ # Custom types defined in this database.
+ # Note that some types may not work with other database engines. Be careful if changing database.
+ create_enum "pricing_types", ["fixed", "per_person"]
+
+ create_table "expenses", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+ t.string "name"
+ t.decimal "amount"
+ t.enum "pricing_type", default: "fixed", null: false, enum_type: "pricing_types"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
end
diff --git a/spec/models/expense_spec.rb b/spec/models/expense_spec.rb
new file mode 100644
index 0000000..5ad50a3
--- /dev/null
+++ b/spec/models/expense_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe Expense, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end