Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/1/create asset #11

Merged
merged 13 commits into from
Jan 25, 2023
2 changes: 2 additions & 0 deletions app/assets/stylesheets/application.sass.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@

// Components
@import "components/btn";
@import "components/cards";
@import "components/error_message";
@import "components/form";
@import "components/navbar";
@import "components/page_title";
@import "components/stock";
@import "components/turbo_progress_bar";
@import "components/visually_hidden";
Expand Down
19 changes: 19 additions & 0 deletions app/assets/stylesheets/components/_cards.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.cards {
display: flex;
justify-content: start;
align-items: center;
gap: var(--space-m);
flex-wrap: wrap;
-ms-flex-wrap: wrap;

.card {
background-color: var(--color-white);
border-radius: var(--border-radius);
box-shadow: var(--shadow-large);
padding: var(--space-xs);

@include media(tabletAndUp) {
padding: var(--space-l);
}
}
}
4 changes: 4 additions & 0 deletions app/assets/stylesheets/components/_page_title.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.page-title {
display: flex;
margin-bottom: var(--space-l);
}
5 changes: 5 additions & 0 deletions app/controllers/assets_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AssetsController < ApplicationController
def index
@assets = current_user.assets
end
end
9 changes: 9 additions & 0 deletions app/models/asset.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Asset < ApplicationRecord
belongs_to :user
belongs_to :stock

validates :stock, :user, :amount, :average_price, :total_invested, presence: true
validates :stock_id, uniqueness: { scope: [:user_id] }

validates :average_price, :amount, :total_invested, numericality: { greater_than_or_equal_to: 0 }
end
2 changes: 2 additions & 0 deletions app/models/stock.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class Stock < ApplicationRecord
has_many :assets, dependent: :restrict_with_error

validates :code, presence: true
validates :code, length: { in: 5..6 }
end
3 changes: 3 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable

has_many :assets, dependent: :delete_all
has_many :stocks, through: :assets

validates :email, :password, :password_confirmation, presence: true

def name
Expand Down
16 changes: 16 additions & 0 deletions app/views/assets/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<main class="container">
<div class="page-title">
<h1><%= t(:asset, scope: 'activerecord.models').pluralize %></h1>
</div>

<div class="assets cards">
<% @assets.each do |asset|%>
<div class="card">
<p><strong><%= Asset.human_attribute_name('stock_code') %></strong>: <%= asset.stock.code %></p>
<p><strong><%= Asset.human_attribute_name('amount') %></strong>: <%= asset.amount %></p>
<p><strong><%= Asset.human_attribute_name('average_price') %></strong>: <%= number_to_currency asset.average_price %></p>
<p><strong><%= Asset.human_attribute_name('total_invested') %></strong>: <%= number_to_currency asset.total_invested %></p>
</div>
<% end %>
</div>
</main>
18 changes: 11 additions & 7 deletions config/locales/activerecord/pt-BR.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
pt-BR:
activerecord:
models:
asset: 'Ativo'
stock: 'Ação'
user: 'Usuário'
attributes:
stock:
code: 'Código'
name: 'Nome'
asset:
amount: 'Quant.'
average_price: 'P. médio'
total_invested: 'T. invest.'
user: 'Usuário'
stock: 'Ação'
stock_code: 'Código'
errors:
messages:
record_invalid: 'A validação falhou: %{errors}'
restrict_dependent_destroy:
has_one: 'Não é possível excluir o registro pois existe um %{record} dependente'
has_many: 'Não é possível excluir o registro pois existem %{record} dependentes'
models:
stock:
attributes:
code:
too_short: 'tamanho pequeno'
too_long: 'tamanho grande'
blank: 'é obrigatório'
34 changes: 3 additions & 31 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t "hello"
#
# In views, this is aliased to just `t`:
#
# <%= t("hello") %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# The following keys must be escaped otherwise they will not be retrieved by
# the default I18n backend:
#
# true, false, on, off, yes, no
#
# Instead, surround them with single quotes.
#
# en:
# "true": "foo"
#
# To learn more, please read the Rails Internationalization guide
# available at https://guides.rubyonrails.org/i18n.html.

en:
hello: "Hello world"

routes:
assets: 'my-assets'
111 changes: 111 additions & 0 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,114 @@
pt-BR:
name_app: 'Minha carteira'
hello: 'Olá'

routes:
assets: 'ativos'
users: 'users'

helpers:
select:
prompt: 'Por favor selecione'
submit:
create: 'Criar %{model}'
submit: 'Salvar %{model}'
update: 'Atualizar %{model}'

number:
currency:
format:
delimiter: '.'
format: '%u %n'
precision: 2
separator: ','
significant: false
strip_insignificant_zeros: false
unit: R$
format:
delimiter: '.'
precision: 3
separator: ','
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: '%n %u'
units:
billion:
one: 'bilhão'
other: 'bilhões'
million:
one: 'milhão'
other: 'milhões'
quadrillion:
one: 'quatrilhão'
other: 'quatrilhões'
thousand: 'mil'
trillion:
one: 'trilhão'
other: 'trilhões'
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: '%n %u'
units:
byte:
one: 'Byte'
other: 'Bytes'
eb: 'EB'
gb: 'GB'
kb: 'KB'
mb: 'MB'
pb: 'PB'
tb: 'TB'
percentage:
format:
delimiter: '.'
format: '%n%'
precision:
format:
delimiter:

errors:
format: '%{attribute} %{message}'
messages:
accepted: 'deve ser aceito'
access_denied: 'Acesso Negado'
blank: 'não pode ficar em branco'
confirmation: 'não é igual a %{attribute}'
empty: 'não pode ficar vazio'
equal_to: 'deve ser igual a %{count}'
even: 'deve ser par'
exclusion: 'não está disponível'
greater_than: 'deve ser maior que %{count}'
greater_than_or_equal_to: 'deve ser maior ou igual a %{count}'
inclusion: 'não está incluído na lista'
invalid: 'não é válido'
less_than: 'deve ser menor que %{count}'
less_than_or_equal_to: 'deve ser menor ou igual a %{count}'
model_invalid: 'A validação falhou: %{errors}'
not_a_number: 'não é um número'
not_an_integer: 'não é um número inteiro'
odd: 'deve ser ímpar'
other_than: 'deve ser diferente de %{count}'
present: 'deve ficar em branco'
required: 'é obrigatório(a)'
taken: 'já está em uso'
too_long:
one: 'é muito longo (máximo: 1 caracter)'
other: 'é muito longo (máximo: %{count} caracteres)'
too_short:
one: 'é muito curto (mínimo: 1 caracter)'
other: 'é muito curto (mínimo: %{count} caracteres)'
wrong_length:
one: 'não possui o tamanho esperado (1 caracter)'
other: 'não possui o tamanho esperado (%{count} caracteres)'
template:
body: 'Por favor, verifique o(s) seguinte(s) campo(s):'
header:
one: 'Não foi possível gravar %{model}: 1 erro'
other: 'Não foi possível gravar %{model}: %{count} erros'
10 changes: 9 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Rails.application.routes.draw do
root to: 'home#index'
unauthenticated :user do
root to: 'home#index', as: :unauthenticated_user_root
end

authenticated :user do
root to: 'assets#index', as: :authenticated_user_root
end

get 'home', to: 'home#index'
devise_for :users

resources :assets, only: :index, path: I18n.t('routes.assets')
end
14 changes: 14 additions & 0 deletions db/migrate/20230124172554_create_assets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateAssets < ActiveRecord::Migration[7.0]
def change
create_table :assets, id: :uuid, bulk: true do |t|
t.integer :amount, default: 0
t.float :average_price, default: 0
t.float :total_invested, default: 0
t.references :user, null: false, foreign_key: true, type: :uuid
t.references :stock, null: false, foreign_key: true, type: :uuid
t.index [:stock_id, :user_id], unique: true

t.timestamps
end
end
end
17 changes: 16 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions spec/factories/assets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FactoryBot.define do
factory :asset do
amount { 1 }
average_price { 1.5 }
total_invested { 1.5 }
user { create(:user) }
stock { create(:stock) }
end
end
19 changes: 19 additions & 0 deletions spec/models/asset_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'rails_helper'

RSpec.describe Asset, type: :model do
describe 'validates' do
context 'presence' do
it { should validate_presence_of(:average_price) }
it { should validate_presence_of(:total_invested) }
it { should validate_presence_of(:amount) }
it { should validate_presence_of(:user) }
it { should validate_presence_of(:stock) }
end

context 'validate numericality' do
it { should validate_numericality_of(:average_price).is_greater_than_or_equal_to(0) }
it { should validate_numericality_of(:amount).is_greater_than_or_equal_to(0) }
it { should validate_numericality_of(:total_invested).is_greater_than_or_equal_to(0) }
end
end
end
26 changes: 26 additions & 0 deletions spec/requests/asset_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'rails_helper'

RSpec.describe 'Asset', type: :request do
describe 'GET /index' do
context 'when user is logged' do
before :each do
user = create(:user)
create_list(:asset, 3, user:)

sign_in(user)
end

it 'returns http success' do
get assets_path
expect(response).to have_http_status(:success)
end
end

context 'when not logged' do
it 'returns http success' do
get assets_path
expect(response).to have_http_status(:redirect)
end
end
end
end
7 changes: 7 additions & 0 deletions spec/support/devise.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'devise'

RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :request

config.infer_spec_type_from_file_location!
end