feat: added spendings for bubbles
Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
parent
11f5929a1a
commit
edf60e9557
@ -9,6 +9,11 @@ class BubblesController < ApplicationController
|
||||
@bubble = Bubble.new
|
||||
end
|
||||
|
||||
def show
|
||||
@bubble = Bubble.find(params[:id])
|
||||
@spendings = @bubble.spendings.unscope(:order).order(created_at: :desc)
|
||||
end
|
||||
|
||||
def create
|
||||
if Bubble.new(allowed_params).save
|
||||
redirect_to bubbles_path, flash: { success: "Créé" }
|
||||
|
23
app/controllers/spendings_controller.rb
Normal file
23
app/controllers/spendings_controller.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SpendingsController < ApplicationController
|
||||
def new
|
||||
@bubble = Bubble.find(params[:bubble_id])
|
||||
@spending = Spending.new
|
||||
end
|
||||
|
||||
def create
|
||||
@bubble = Bubble.find(params[:bubble_id])
|
||||
if @bubble.spendings.new(allowed_params).save
|
||||
redirect_to bubble_path(@bubble), flash: { success: "Créé" }
|
||||
else
|
||||
redirect_to new_bubble_spending_path(@bubble), flash: { error: "Pas créé" }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_params
|
||||
params.require(:spending).permit(:amount, :description, :owner_id)
|
||||
end
|
||||
end
|
@ -21,4 +21,5 @@
|
||||
class Bubble < ApplicationRecord
|
||||
validates :name, presence: true, allow_blank: false
|
||||
belongs_to :owner, class_name: "User"
|
||||
has_many :spendings
|
||||
end
|
||||
|
25
app/models/spending.rb
Normal file
25
app/models/spending.rb
Normal file
@ -0,0 +1,25 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: spendings
|
||||
#
|
||||
# id :uuid not null, primary key
|
||||
# amount :decimal(, ) default(0.0), not null
|
||||
# description :text default(""), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# bubble_id :uuid not null
|
||||
# owner_id :uuid not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_spendings_on_bubble_id (bubble_id)
|
||||
# index_spendings_on_owner_id (owner_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (owner_id => users.id)
|
||||
#
|
||||
class Spending < ApplicationRecord
|
||||
belongs_to :owner, class_name: "User"
|
||||
belongs_to :bubble
|
||||
end
|
@ -23,4 +23,5 @@ class User < ApplicationRecord
|
||||
:recoverable, :rememberable, :validatable
|
||||
|
||||
has_many :bubbles, foreign_key: :owner_id
|
||||
has_many :spendings, foreign_key: :owner_id
|
||||
end
|
||||
|
@ -11,6 +11,7 @@
|
||||
<td><%= bubble.name %></td>
|
||||
<td><%= bubble.description %></td>
|
||||
<td>
|
||||
<%= link_to "Voir", bubble_path(bubble) %>
|
||||
<%= link_to "Éditer", edit_bubble_path(bubble) %>
|
||||
<%= link_to "Supprimer", bubble_confirm_destroy_path(bubble) %>
|
||||
</td>
|
||||
|
22
app/views/bubbles/show.html.erb
Normal file
22
app/views/bubbles/show.html.erb
Normal file
@ -0,0 +1,22 @@
|
||||
<h1><%= @bubble.name %></h1>
|
||||
<p><%= @bubble.description %></p>
|
||||
<%= link_to "Nouvelle dépense", new_bubble_spending_path(@bubble) %>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Montant</th>
|
||||
<th>Origine</th>
|
||||
<th>Raison</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @spendings.each do |spending| %>
|
||||
<tr>
|
||||
<td><%= number_to_currency(spending.amount, unit: "€") %></td>
|
||||
<td><%= spending.owner.email %></td>
|
||||
<td><%= spending.description %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
1
app/views/spendings/new.html.erb
Normal file
1
app/views/spendings/new.html.erb
Normal file
@ -0,0 +1 @@
|
||||
<%= render partial: "spendings/shared/form", locals: { spending: @spending, bubble: @bubble } %>
|
20
app/views/spendings/shared/_form.html.erb
Normal file
20
app/views/spendings/shared/_form.html.erb
Normal file
@ -0,0 +1,20 @@
|
||||
<%= form_for spending, url: spending.persisted? ? spending_path(spending) : bubble_spendings_path(bubble) do |f| %>
|
||||
|
||||
<div>
|
||||
<%= f.label :amount, "Valeur" %>
|
||||
<%= f.number_field :amount, required: true, step: 0.01 %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.label :description, "Description" %>
|
||||
<%= f.text_area :description %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= f.label :owner_id, "Créateur" %>
|
||||
<%= f.select :owner_id, User.all.collect {|u| [ u.email, u.id ] }, selected: bubble.owner_id || current_user.id %>
|
||||
</div>
|
||||
|
||||
<%= f.submit "Sauvegarder" %>
|
||||
|
||||
<% end %>
|
@ -18,5 +18,7 @@ module DebtManager
|
||||
#
|
||||
# config.time_zone = "Central Time (US & Canada)"
|
||||
# config.eager_load_paths << Rails.root.join("extras")
|
||||
|
||||
config.i18n.default_locale = :fr
|
||||
end
|
||||
end
|
||||
|
221
config/locales/fr.yml
Normal file
221
config/locales/fr.yml
Normal file
@ -0,0 +1,221 @@
|
||||
---
|
||||
fr:
|
||||
activerecord:
|
||||
errors:
|
||||
messages:
|
||||
record_invalid: 'La validation a échoué : %{errors}'
|
||||
restrict_dependent_destroy:
|
||||
has_one: Vous ne pouvez pas supprimer l'enregistrement car un(e) %{record}
|
||||
dépendant(e) existe
|
||||
has_many: Vous ne pouvez pas supprimer l'enregistrement parce que les %{record}
|
||||
dépendants existent
|
||||
date:
|
||||
abbr_day_names:
|
||||
- dim
|
||||
- lun
|
||||
- mar
|
||||
- mer
|
||||
- jeu
|
||||
- ven
|
||||
- sam
|
||||
abbr_month_names:
|
||||
-
|
||||
- jan.
|
||||
- fév.
|
||||
- mars
|
||||
- avr.
|
||||
- mai
|
||||
- juin
|
||||
- juil.
|
||||
- août
|
||||
- sept.
|
||||
- oct.
|
||||
- nov.
|
||||
- déc.
|
||||
day_names:
|
||||
- dimanche
|
||||
- lundi
|
||||
- mardi
|
||||
- mercredi
|
||||
- jeudi
|
||||
- vendredi
|
||||
- samedi
|
||||
formats:
|
||||
default: "%d/%m/%Y"
|
||||
long: "%-d %B %Y"
|
||||
short: "%-d %b"
|
||||
month_names:
|
||||
-
|
||||
- janvier
|
||||
- février
|
||||
- mars
|
||||
- avril
|
||||
- mai
|
||||
- juin
|
||||
- juillet
|
||||
- août
|
||||
- septembre
|
||||
- octobre
|
||||
- novembre
|
||||
- décembre
|
||||
order:
|
||||
- :day
|
||||
- :month
|
||||
- :year
|
||||
datetime:
|
||||
distance_in_words:
|
||||
about_x_hours:
|
||||
one: environ une heure
|
||||
other: environ %{count} heures
|
||||
about_x_months:
|
||||
one: environ un mois
|
||||
other: environ %{count} mois
|
||||
about_x_years:
|
||||
one: environ un an
|
||||
other: environ %{count} ans
|
||||
almost_x_years:
|
||||
one: presque un an
|
||||
other: presque %{count} ans
|
||||
half_a_minute: une demi‑minute
|
||||
less_than_x_seconds:
|
||||
zero: moins d'une seconde
|
||||
one: moins d'une seconde
|
||||
other: moins de %{count} secondes
|
||||
less_than_x_minutes:
|
||||
zero: moins d'une minute
|
||||
one: moins d'une minute
|
||||
other: moins de %{count} minutes
|
||||
over_x_years:
|
||||
one: plus d'un an
|
||||
other: plus de %{count} ans
|
||||
x_seconds:
|
||||
one: "%{count} seconde"
|
||||
other: "%{count} secondes"
|
||||
x_minutes:
|
||||
one: "%{count} minute"
|
||||
other: "%{count} minutes"
|
||||
x_days:
|
||||
one: "%{count} jour"
|
||||
other: "%{count} jours"
|
||||
x_months:
|
||||
one: "%{count} mois"
|
||||
other: "%{count} mois"
|
||||
x_years:
|
||||
one: "%{count} an"
|
||||
other: "%{count} ans"
|
||||
prompts:
|
||||
second: Seconde
|
||||
minute: Minute
|
||||
hour: Heure
|
||||
day: Jour
|
||||
month: Mois
|
||||
year: Année
|
||||
errors:
|
||||
format: "%{attribute} %{message}"
|
||||
messages:
|
||||
accepted: doit être accepté(e)
|
||||
blank: doit être rempli(e)
|
||||
confirmation: ne concorde pas avec %{attribute}
|
||||
empty: doit être rempli(e)
|
||||
equal_to: doit être égal à %{count}
|
||||
even: doit être pair
|
||||
exclusion: n'est pas disponible
|
||||
greater_than: doit être supérieur à %{count}
|
||||
greater_than_or_equal_to: doit être supérieur ou égal à %{count}
|
||||
in: doit être dans l'intervalle %{count}
|
||||
inclusion: n'est pas inclus(e) dans la liste
|
||||
invalid: n'est pas valide
|
||||
less_than: doit être inférieur à %{count}
|
||||
less_than_or_equal_to: doit être inférieur ou égal à %{count}
|
||||
model_invalid: 'Validation échouée : %{errors}'
|
||||
not_a_number: n'est pas un nombre
|
||||
not_an_integer: doit être un nombre entier
|
||||
odd: doit être impair
|
||||
other_than: doit être différent de %{count}
|
||||
present: doit être vide
|
||||
required: doit exister
|
||||
taken: est déjà utilisé(e)
|
||||
too_long:
|
||||
one: est trop long (pas plus d'un caractère)
|
||||
other: est trop long (pas plus de %{count} caractères)
|
||||
too_short:
|
||||
one: est trop court (au moins un caractère)
|
||||
other: est trop court (au moins %{count} caractères)
|
||||
wrong_length:
|
||||
one: ne fait pas la bonne longueur (doit comporter un seul caractère)
|
||||
other: ne fait pas la bonne longueur (doit comporter %{count} caractères)
|
||||
template:
|
||||
body: 'Veuillez vérifier les champs suivants : '
|
||||
header:
|
||||
one: 'Impossible d''enregistrer ce(tte) %{model} : %{count} erreur'
|
||||
other: 'Impossible d''enregistrer ce(tte) %{model} : %{count} erreurs'
|
||||
helpers:
|
||||
select:
|
||||
prompt: Veuillez sélectionner
|
||||
submit:
|
||||
create: Créer un(e) %{model}
|
||||
submit: Enregistrer ce(tte) %{model}
|
||||
update: Modifier ce(tte) %{model}
|
||||
number:
|
||||
currency:
|
||||
format:
|
||||
delimiter: " "
|
||||
format: "%n %u"
|
||||
precision: 2
|
||||
separator: ","
|
||||
significant: false
|
||||
strip_insignificant_zeros: false
|
||||
unit: "€"
|
||||
format:
|
||||
delimiter: " "
|
||||
precision: 3
|
||||
round_mode: default
|
||||
separator: ","
|
||||
significant: false
|
||||
strip_insignificant_zeros: false
|
||||
human:
|
||||
decimal_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
billion: milliard
|
||||
million: million
|
||||
quadrillion: million de milliards
|
||||
thousand: millier
|
||||
trillion: billion
|
||||
unit: ''
|
||||
format:
|
||||
delimiter: ''
|
||||
precision: 3
|
||||
significant: true
|
||||
strip_insignificant_zeros: true
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: octet
|
||||
other: octets
|
||||
eb: Eo
|
||||
gb: Go
|
||||
kb: ko
|
||||
mb: Mo
|
||||
pb: Po
|
||||
tb: To
|
||||
percentage:
|
||||
format:
|
||||
delimiter: ''
|
||||
format: "%n%"
|
||||
precision:
|
||||
format:
|
||||
delimiter: ''
|
||||
support:
|
||||
array:
|
||||
last_word_connector: " et "
|
||||
two_words_connector: " et "
|
||||
words_connector: ", "
|
||||
time:
|
||||
am: am
|
||||
formats:
|
||||
default: "%d %B %Y %Hh %Mmin %Ss"
|
||||
long: "%A %d %B %Y %Hh%M"
|
||||
short: "%d %b %Hh%M"
|
||||
pm: pm
|
@ -6,7 +6,8 @@ Rails.application.routes.draw do
|
||||
# Defines the root path route ("/")
|
||||
get :home, controller: :profile
|
||||
|
||||
resources :bubbles, except: [:show] do
|
||||
resources :bubbles do
|
||||
resources :spendings, only: [:new, :create]
|
||||
get :confirm_destroy
|
||||
end
|
||||
end
|
||||
|
12
db/migrate/20231231172005_add_spending_to_bubbles.rb
Normal file
12
db/migrate/20231231172005_add_spending_to_bubbles.rb
Normal file
@ -0,0 +1,12 @@
|
||||
class AddSpendingToBubbles < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :spendings, id: :uuid do |t|
|
||||
t.decimal :amount, null: false, default: 0
|
||||
t.text :description, null: false, default: ""
|
||||
t.references :bubble, type: :uuid, null: false
|
||||
t.references :owner, type: :uuid, foreign_key: { to_table: :users }, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
14
db/schema.rb
generated
14
db/schema.rb
generated
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_12_10_091848) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_12_31_172005) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pgcrypto"
|
||||
enable_extension "plpgsql"
|
||||
@ -25,6 +25,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_10_091848) do
|
||||
t.index ["owner_id"], name: "index_bubbles_on_owner_id"
|
||||
end
|
||||
|
||||
create_table "spendings", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.decimal "amount", default: "0.0", null: false
|
||||
t.text "description", default: "", null: false
|
||||
t.uuid "bubble_id", null: false
|
||||
t.uuid "owner_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["bubble_id"], name: "index_spendings_on_bubble_id"
|
||||
t.index ["owner_id"], name: "index_spendings_on_owner_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
|
||||
@ -38,4 +49,5 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_10_091848) do
|
||||
end
|
||||
|
||||
add_foreign_key "bubbles", "users", column: "owner_id"
|
||||
add_foreign_key "spendings", "users", column: "owner_id"
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user