mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-08 06:55:21 +02:00
Portfolio rough-in
This commit is contained in:
parent
bac8ffaca9
commit
0399f43252
18 changed files with 286 additions and 3 deletions
63
app/controllers/portfolios_controller.rb
Normal file
63
app/controllers/portfolios_controller.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
class PortfoliosController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_portfolio, only: %i[ show edit update destroy ]
|
||||
|
||||
def index
|
||||
@portfolios = current_user.portfolios
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
@portfolio = Portfolio.new
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def create
|
||||
@portfolio = current_user.portfolios.new(portfolio_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @portfolio.save
|
||||
format.html { redirect_to portfolio_url(@portfolio), notice: "Portfolio was successfully created." }
|
||||
format.json { render :show, status: :created, location: @portfolio }
|
||||
else
|
||||
format.html { render :new, status: :unprocessable_entity }
|
||||
format.json { render json: @portfolio.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
respond_to do |format|
|
||||
if @portfolio.update(portfolio_params)
|
||||
format.html { redirect_to portfolio_url(@portfolio), notice: "Portfolio was successfully updated." }
|
||||
format.json { render :show, status: :ok, location: @portfolio }
|
||||
else
|
||||
format.html { render :edit, status: :unprocessable_entity }
|
||||
format.json { render json: @portfolio.errors, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@portfolio.destroy!
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to portfolios_url, notice: "Portfolio was successfully destroyed." }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def set_portfolio
|
||||
@portfolio = current_user.portfolios.find(params[:id])
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def portfolio_params
|
||||
params.require(:portfolio).permit(:name)
|
||||
end
|
||||
end
|
2
app/helpers/portfolios_helper.rb
Normal file
2
app/helpers/portfolios_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
module PortfoliosHelper
|
||||
end
|
5
app/models/portfolio.rb
Normal file
5
app/models/portfolio.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class Portfolio < ApplicationRecord
|
||||
belongs_to :user
|
||||
|
||||
validates :name, presence: true
|
||||
end
|
|
@ -2,4 +2,6 @@ class User < ApplicationRecord
|
|||
devise :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :validatable,
|
||||
:confirmable, :lockable, :timeoutable, :trackable
|
||||
|
||||
has_many :portfolios, dependent: :destroy
|
||||
end
|
||||
|
|
|
@ -33,12 +33,12 @@
|
|||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to root_path, class: "flex p-2 text-sm font-semibold leading-6 text-gray-600 rounded-md group gap-x-3" do %>
|
||||
<%= link_to portfolios_path, class: "flex p-2 text-sm font-semibold leading-6 text-gray-600 rounded-md group gap-x-3" do %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-blue-600 shrink-0">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 14.15v4.25c0 1.094-.787 2.036-1.872 2.18-2.087.277-4.216.42-6.378.42s-4.291-.143-6.378-.42c-1.085-.144-1.872-1.086-1.872-2.18v-4.25m16.5 0a2.18 2.18 0 0 0 .75-1.661V8.706c0-1.081-.768-2.015-1.837-2.175a48.114 48.114 0 0 0-3.413-.387m4.5 8.006c-.194.165-.42.295-.673.38A23.978 23.978 0 0 1 12 15.75c-2.648 0-5.195-.429-7.577-1.22a2.016 2.016 0 0 1-.673-.38m0 0A2.18 2.18 0 0 1 3 12.489V8.706c0-1.081.768-2.015 1.837-2.175a48.111 48.111 0 0 1 3.413-.387m7.5 0V5.25A2.25 2.25 0 0 0 13.5 3h-3a2.25 2.25 0 0 0-2.25 2.25v.894m7.5 0a48.667 48.667 0 0 0-7.5 0M12 12.75h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
|
||||
Portfolio
|
||||
Portfolios
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
22
app/views/portfolios/_form.html.erb
Normal file
22
app/views/portfolios/_form.html.erb
Normal file
|
@ -0,0 +1,22 @@
|
|||
<%= form_with(model: portfolio, class: "contents") do |form| %>
|
||||
<% if portfolio.errors.any? %>
|
||||
<div id="error_explanation" class="px-3 py-2 mt-3 font-medium text-red-500 rounded-lg bg-red-50">
|
||||
<h2><%= pluralize(portfolio.errors.count, "error") %> prohibited this portfolio from being saved:</h2>
|
||||
|
||||
<ul>
|
||||
<% portfolio.errors.each do |error| %>
|
||||
<li><%= error.full_message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="my-5">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
|
||||
</div>
|
||||
|
||||
<div class="inline">
|
||||
<%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
|
||||
</div>
|
||||
<% end %>
|
11
app/views/portfolios/_portfolio.html.erb
Normal file
11
app/views/portfolios/_portfolio.html.erb
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div id="<%= dom_id portfolio %>">
|
||||
<p class="my-5">
|
||||
<%= portfolio.name %>
|
||||
</p>
|
||||
|
||||
<% if action_name != "show" %>
|
||||
<%= link_to "Show this portfolio", portfolio, class: "rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
<%= link_to "Edit this portfolio", edit_portfolio_path(portfolio), class: "rounded-lg py-3 ml-2 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
<hr class="mt-6">
|
||||
<% end %>
|
||||
</div>
|
8
app/views/portfolios/edit.html.erb
Normal file
8
app/views/portfolios/edit.html.erb
Normal file
|
@ -0,0 +1,8 @@
|
|||
<div class="mx-auto md:w-2/3 w-full">
|
||||
<h1 class="font-bold text-4xl">Editing portfolio</h1>
|
||||
|
||||
<%= render "form", portfolio: @portfolio %>
|
||||
|
||||
<%= link_to "Show this portfolio", @portfolio, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
<%= link_to "Back to portfolios", portfolios_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
</div>
|
18
app/views/portfolios/index.html.erb
Normal file
18
app/views/portfolios/index.html.erb
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div class="w-full">
|
||||
<% if notice.present? %>
|
||||
<p class="inline-block px-3 py-2 mb-5 font-medium text-green-500 rounded-lg bg-green-50" id="notice"><%= notice %></p>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-4xl font-bold">Portfolios</h1>
|
||||
<%= link_to "New portfolio", new_portfolio_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
|
||||
</div>
|
||||
|
||||
<ul id="portfolios" class="min-w-full prose">
|
||||
<% @portfolios.each do |portfolio| %>
|
||||
<li>
|
||||
<%= link_to portfolio.name, portfolio %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
7
app/views/portfolios/new.html.erb
Normal file
7
app/views/portfolios/new.html.erb
Normal file
|
@ -0,0 +1,7 @@
|
|||
<div class="mx-auto md:w-2/3 w-full">
|
||||
<h1 class="font-bold text-4xl">New portfolio</h1>
|
||||
|
||||
<%= render "form", portfolio: @portfolio %>
|
||||
|
||||
<%= link_to "Back to portfolios", portfolios_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
</div>
|
17
app/views/portfolios/show.html.erb
Normal file
17
app/views/portfolios/show.html.erb
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div class="flex w-full">
|
||||
<% if notice.present? %>
|
||||
<p class="inline-block px-3 py-2 mb-5 font-medium text-green-500 rounded-lg bg-green-50" id="notice"><%= notice %></p>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-4xl font-bold"><%= @portfolio.name %></h2>
|
||||
|
||||
<div class="inline-block ml-2">
|
||||
<%= link_to "Edit this portfolio", edit_portfolio_path(@portfolio), class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
<div class="inline-block ml-2">
|
||||
<%= button_to "Destroy this portfolio", portfolio_path(@portfolio), method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %>
|
||||
</div>
|
||||
<%= link_to "Back to portfolios", portfolios_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,4 +1,6 @@
|
|||
Rails.application.routes.draw do
|
||||
resources :portfolios
|
||||
|
||||
devise_for :users
|
||||
|
||||
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
||||
|
|
10
db/migrate/20240102020519_create_portfolios.rb
Normal file
10
db/migrate/20240102020519_create_portfolios.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class CreatePortfolios < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :portfolios, id: :uuid do |t|
|
||||
t.references :user, null: false, foreign_key: true, type: :uuid
|
||||
t.string :name
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
11
db/schema.rb
generated
11
db/schema.rb
generated
|
@ -10,11 +10,19 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.2].define(version: 2024_01_01_232802) do
|
||||
ActiveRecord::Schema[7.2].define(version: 2024_01_02_020519) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
enable_extension "plpgsql"
|
||||
|
||||
create_table "portfolios", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.uuid "user_id", null: false
|
||||
t.string "name"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["user_id"], name: "index_portfolios_on_user_id"
|
||||
end
|
||||
|
||||
create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
|
@ -41,4 +49,5 @@ ActiveRecord::Schema[7.2].define(version: 2024_01_01_232802) do
|
|||
t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
|
||||
end
|
||||
|
||||
add_foreign_key "portfolios", "users"
|
||||
end
|
||||
|
|
48
test/controllers/portfolios_controller_test.rb
Normal file
48
test/controllers/portfolios_controller_test.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
require "test_helper"
|
||||
|
||||
class PortfoliosControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@portfolio = portfolios(:one)
|
||||
end
|
||||
|
||||
test "should get index" do
|
||||
get portfolios_url
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should get new" do
|
||||
get new_portfolio_url
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should create portfolio" do
|
||||
assert_difference("Portfolio.count") do
|
||||
post portfolios_url, params: { portfolio: { name: @portfolio.name, user_id: @portfolio.user_id } }
|
||||
end
|
||||
|
||||
assert_redirected_to portfolio_url(Portfolio.last)
|
||||
end
|
||||
|
||||
test "should show portfolio" do
|
||||
get portfolio_url(@portfolio)
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should get edit" do
|
||||
get edit_portfolio_url(@portfolio)
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "should update portfolio" do
|
||||
patch portfolio_url(@portfolio), params: { portfolio: { name: @portfolio.name, user_id: @portfolio.user_id } }
|
||||
assert_redirected_to portfolio_url(@portfolio)
|
||||
end
|
||||
|
||||
test "should destroy portfolio" do
|
||||
assert_difference("Portfolio.count", -1) do
|
||||
delete portfolio_url(@portfolio)
|
||||
end
|
||||
|
||||
assert_redirected_to portfolios_url
|
||||
end
|
||||
end
|
9
test/fixtures/portfolios.yml
vendored
Normal file
9
test/fixtures/portfolios.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||
|
||||
one:
|
||||
user: one
|
||||
name: MyString
|
||||
|
||||
two:
|
||||
user: two
|
||||
name: MyString
|
7
test/models/portfolio_test.rb
Normal file
7
test/models/portfolio_test.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require "test_helper"
|
||||
|
||||
class PortfolioTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
43
test/system/portfolios_test.rb
Normal file
43
test/system/portfolios_test.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require "application_system_test_case"
|
||||
|
||||
class PortfoliosTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
@portfolio = portfolios(:one)
|
||||
end
|
||||
|
||||
test "visiting the index" do
|
||||
visit portfolios_url
|
||||
assert_selector "h1", text: "Portfolios"
|
||||
end
|
||||
|
||||
test "should create portfolio" do
|
||||
visit portfolios_url
|
||||
click_on "New portfolio"
|
||||
|
||||
fill_in "Name", with: @portfolio.name
|
||||
fill_in "User", with: @portfolio.user_id
|
||||
click_on "Create Portfolio"
|
||||
|
||||
assert_text "Portfolio was successfully created"
|
||||
click_on "Back"
|
||||
end
|
||||
|
||||
test "should update Portfolio" do
|
||||
visit portfolio_url(@portfolio)
|
||||
click_on "Edit this portfolio", match: :first
|
||||
|
||||
fill_in "Name", with: @portfolio.name
|
||||
fill_in "User", with: @portfolio.user_id
|
||||
click_on "Update Portfolio"
|
||||
|
||||
assert_text "Portfolio was successfully updated"
|
||||
click_on "Back"
|
||||
end
|
||||
|
||||
test "should destroy Portfolio" do
|
||||
visit portfolio_url(@portfolio)
|
||||
click_on "Destroy this portfolio", match: :first
|
||||
|
||||
assert_text "Portfolio was successfully destroyed"
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue