1
0
Fork 0
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:
Josh Pigford 2024-01-01 20:18:34 -06:00
parent bac8ffaca9
commit 0399f43252
18 changed files with 286 additions and 3 deletions

View 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

View file

@ -0,0 +1,2 @@
module PortfoliosHelper
end

5
app/models/portfolio.rb Normal file
View file

@ -0,0 +1,5 @@
class Portfolio < ApplicationRecord
belongs_to :user
validates :name, presence: true
end

View file

@ -2,4 +2,6 @@ class User < ApplicationRecord
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :recoverable, :rememberable, :validatable,
:confirmable, :lockable, :timeoutable, :trackable :confirmable, :lockable, :timeoutable, :trackable
has_many :portfolios, dependent: :destroy
end end

View file

@ -33,12 +33,12 @@
<% end %> <% end %>
</li> </li>
<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"> <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" /> <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> </svg>
Portfolio Portfolios
<% end %> <% end %>
</li> </li>
</ul> </ul>

View 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 %>

View 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>

View 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>

View 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>

View 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>

View 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>

View file

@ -1,4 +1,6 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :portfolios
devise_for :users devise_for :users
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.

View 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
View file

@ -10,11 +10,19 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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 # These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto" enable_extension "pgcrypto"
enable_extension "plpgsql" 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| create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "email", default: "", null: false t.string "email", default: "", null: false
t.string "encrypted_password", 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 t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end end
add_foreign_key "portfolios", "users"
end end

View 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
View 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

View file

@ -0,0 +1,7 @@
require "test_helper"
class PortfolioTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

View 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