barcas! al abordaje!

This commit is contained in:
fauno 2019-08-03 13:23:52 -03:00
parent d669875815
commit ac21341d49
No known key found for this signature in database
GPG key ID: 456032D717A4CD9C
18 changed files with 201 additions and 41 deletions

View file

@ -6,17 +6,18 @@
class ConsensosController < ApplicationController class ConsensosController < ApplicationController
# Para cualquier acción necesitamos autenticación # Para cualquier acción necesitamos autenticación
before_action :authenticate! before_action :authenticate!
before_action :find_barca!
# GET /consensos # GET /barcas/:barca_id/consensos
# #
# Podemos ver todos los consensos # Podemos ver todos los consensos de una barca
# #
# @return [Array] [ consensos ] # @return [Array] [ consensos ]
def index def index
@consensos = Consenso.all.order(:created_at, :desc) @consensos = @barca.consensos.order(:created_at, :desc)
end end
# GET /consensos/:id # GET /barcas/:barca_id/consensos/:id
# #
# Podemos ver uno solo sabiendo su ID # Podemos ver uno solo sabiendo su ID
# #
@ -26,13 +27,13 @@ class ConsensosController < ApplicationController
# pirata: @pirata, # pirata: @pirata,
# posiciones: [] } # posiciones: [] }
def show def show
@consenso = Consenso.find(params[:id]) @consenso = @barca.consensos.find(params[:id])
return if @consenso return if @consenso
render json: {}, status: :not_found render json: {}, status: :not_found
end end
# POST /consensos # POST /barcas/:barca_id/consensos
# #
# Podemos crear uno, enviando un hash con todas las propiedades # Podemos crear uno, enviando un hash con todas las propiedades
# #
@ -42,8 +43,8 @@ class ConsensosController < ApplicationController
# pirata: @pirata, # pirata: @pirata,
# posiciones: [] } # posiciones: [] }
def create def create
@consenso = current_pirata.consensos @consenso = current_pirata.consensos.new(consenso_params)
.new(params.require(:consenso).permit(:titulo, :texto)) @consenso.barca = @barca
if @consenso.save if @consenso.save
render status: :created render status: :created
@ -53,7 +54,7 @@ class ConsensosController < ApplicationController
end end
end end
# DELETE /consensos/:id # DELETE /barcas/:barca_id/consensos/:id
# #
# Eliminar un consenso, solo si no tiene posiciones! # Eliminar un consenso, solo si no tiene posiciones!
# #
@ -63,7 +64,7 @@ class ConsensosController < ApplicationController
# posiciones: [] } # posiciones: [] }
def destroy def destroy
begin begin
@consenso = Consenso.find(params[:id]) @consenso = @barca.consensos.find(params[:id])
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: :not_found render json: {}, status: :not_found
return return
@ -75,4 +76,16 @@ class ConsensosController < ApplicationController
render json: {}, status: :unprocessable_entity render json: {}, status: :unprocessable_entity
end end
end end
private
# Encuentra la barca en los parámetros
def find_barca!
@barca = Barca.find(params[:barca_id])
end
# Parámetros permitidos
def consenso_params
params.require(:consenso).permit(:titulo, :texto)
end
end end

View file

@ -8,8 +8,9 @@
class PosicionesController < ApplicationController class PosicionesController < ApplicationController
# Necesitamos autenticarnos # Necesitamos autenticarnos
before_action :authenticate! before_action :authenticate!
before_action :find_barca!
# POST /consensos/:consenso_id/posiciones # POST /barcas/:barca_id/consensos/:consenso_id/posiciones
# #
# Crea una posición dentro de un consenso # Crea una posición dentro de un consenso
# #
@ -18,7 +19,7 @@ class PosicionesController < ApplicationController
# @return [Hash] { id: @int, estado: @string, comentario: @string, # @return [Hash] { id: @int, estado: @string, comentario: @string,
# pirata: @pirata } # pirata: @pirata }
def create def create
@consenso = Consenso.find(params[:consenso_id]) @consenso = @barca.consensos.find(params[:consenso_id])
@posicion = @consenso.try(:posiciones).try(:build, posicion_params) @posicion = @consenso.try(:posiciones).try(:build, posicion_params)
@posicion.try(:pirata=, current_pirata) @posicion.try(:pirata=, current_pirata)
@ -35,4 +36,8 @@ class PosicionesController < ApplicationController
def posicion_params def posicion_params
params.require(:posicion).permit(:estado, :comentario) params.require(:posicion).permit(:estado, :comentario)
end end
def find_barca!
@barca = Barca.find(params[:barca_id])
end
end end

16
app/models/barca.rb Normal file
View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
# Las barcas agrupan consensos y piratas alrededor de un tema específico
# o relación de afinidad
class Barca < ApplicationRecord
# Tiene muchos consensos
has_many :consensos
# En realidad debería tener una sola tripulación que traiga muchas
# piratas, pero rails es así
has_many :tripulaciones, dependent: :destroy
has_many :piratas, through: :tripulaciones
validates_uniqueness_of :nombre
validates_presence_of :descripcion
end

View file

@ -7,4 +7,6 @@ class Consenso < ApplicationRecord
belongs_to :pirata belongs_to :pirata
# Agrupa muchas posiciones # Agrupa muchas posiciones
has_many :posiciones has_many :posiciones
# Pertenece a una barca
belongs_to :barca
end end

View file

@ -7,6 +7,10 @@ class Pirata < ApplicationRecord
# Y tener posiciones # Y tener posiciones
has_many :posiciones has_many :posiciones
# Puede participar en barcas
has_many :tripulaciones
has_many :barcas, through: :tripulaciones
# Y además una contraseña segura :P # Y además una contraseña segura :P
has_secure_password has_secure_password
# Una por correo # Una por correo

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
# La tripulación de una barca
class Tripulacion < ApplicationRecord
belongs_to :barca
belongs_to :pirata
end

View file

@ -10,6 +10,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.singular 'posiciones', 'posicion' inflect.singular 'posiciones', 'posicion'
inflect.plural 'pirata', 'piratas' inflect.plural 'pirata', 'piratas'
inflect.singular 'piratas', 'pirata' inflect.singular 'piratas', 'pirata'
inflect.plural 'tripulacion', 'tripulaciones'
inflect.singular 'tripulaciones', 'tripulacion'
end end
# These inflection rules are supported but not enabled by default: # These inflection rules are supported but not enabled by default:

View file

@ -4,9 +4,12 @@ Rails.application.routes.draw do
get '/piratas/yo', to: 'piratas#yo' get '/piratas/yo', to: 'piratas#yo'
# No queremos un índice de piratas # No queremos un índice de piratas
resources :piratas, only: %i[create] resources :piratas, only: %i[create]
# Podemos crear consensos pero no modificarlos # Podemos crear barcas y dentro de ellas consensos
resources :consensos, only: %i[index show create destroy] do resources :barcas, only: %i[index show create update destroy] do
# Y solo le podemos agregar posiciones # Podemos crear consensos pero no modificarlos
resources :posiciones, only: %i[create] resources :consensos, only: %i[index show create destroy] do
# Y solo le podemos agregar posiciones
resources :posiciones, only: %i[create]
end
end end
end end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
# Crear las barcas
class CreateBarcas < ActiveRecord::Migration[5.2]
def change
create_table :barcas do |t|
t.timestamps
t.string :nombre, unique: true
t.text :descripcion
end
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
# Las piratas abordan barcas a través de tripulaciones
class CreateTripulaciones < ActiveRecord::Migration[5.2]
def change
create_table :tripulaciones do |t|
t.timestamps
t.belongs_to :barca, index: true
t.belongs_to :pirata, index: true
end
end
end

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
# Los consensos pertenecen a barcas
class AddBarcaToConsenso < ActiveRecord::Migration[5.2]
def change
add_belongs_to :consensos, :barca, index: true
end
end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
# Si no hay una barca, creamos una asamblea general!
class AsambleaGeneral < ActiveRecord::Migration[5.2]
def up
return if Barca.all.count.positive?
barca = Barca.create(nombre: 'Asamblea General',
descripcion: 'En la asamblea general tomamos todas las decisiones que no pasan por barcas.')
Pirata.all.find_each do |pirata|
barca.piratas << pirata
end
barca.save
end
def down
Barca.find_by(nombre: 'Asamblea General').destroy
end
end

View file

@ -2,6 +2,7 @@
class ConsensosControllerTest < ActionDispatch::IntegrationTest class ConsensosControllerTest < ActionDispatch::IntegrationTest
setup do setup do
@barca = create :barca
@pirata = create :pirata @pirata = create :pirata
@auth = { Authorization: ActionController::HttpAuthentication::Basic @auth = { Authorization: ActionController::HttpAuthentication::Basic
.encode_credentials(@pirata.email, @pirata.password) } .encode_credentials(@pirata.email, @pirata.password) }
@ -9,10 +10,10 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
test 'se pueden mostrar' do test 'se pueden mostrar' do
2.times do 2.times do
create :consenso create :consenso, barca: @barca
end end
get consensos_url, as: :json, headers: @auth get barca_consensos_url(@barca), as: :json, headers: @auth
body = JSON.parse(@response.body) body = JSON.parse(@response.body)
assert_equal 200, @response.status assert_equal 200, @response.status
@ -21,7 +22,7 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
test 'al mostrar solo se ven las posiciones resumidas' do test 'al mostrar solo se ven las posiciones resumidas' do
2.times do 2.times do
consenso = create :consenso consenso = create :consenso, barca: @barca
pirata = create :pirata pirata = create :pirata
3.times do 3.times do
@ -29,7 +30,7 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
end end
end end
get consensos_url, as: :json, headers: @auth get barca_consensos_url(@barca), as: :json, headers: @auth
body = JSON.parse(@response.body) body = JSON.parse(@response.body)
body['consensos'].each do |consenso| body['consensos'].each do |consenso|
@ -40,7 +41,9 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
test 'se puede ver uno solo' do test 'se puede ver uno solo' do
consenso = create :consenso, con_posiciones: 2 consenso = create :consenso, con_posiciones: 2
get consenso_url(consenso), as: :json, headers: @auth get barca_consenso_url(consenso.barca, consenso),
as: :json,
headers: @auth
body = JSON.parse(@response.body) body = JSON.parse(@response.body)
assert_equal 200, @response.status assert_equal 200, @response.status
@ -49,26 +52,22 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
end end
test 'al ver uno solo se ve todo el historial de posiciones' do test 'al ver uno solo se ve todo el historial de posiciones' do
consenso = create :consenso consenso = create :consenso, barca: @barca
pirata = create :pirata pirata = create :pirata
3.times do 3.times do
create :posicion, consenso: consenso, pirata: pirata create :posicion, consenso: consenso, pirata: pirata
end end
get consenso_url(consenso), as: :json, headers: @auth get barca_consenso_url(@barca, consenso), as: :json, headers: @auth
body = JSON.parse(@response.body) body = JSON.parse(@response.body)
assert_equal 3, body['posiciones'].size assert_equal 3, body['posiciones'].size
end end
test 'se pueden crear' do test 'se pueden crear' do
post consensos_url, as: :json, headers: @auth, params: { post barca_consensos_url(@barca), as: :json, headers: @auth,
consenso: { params: { consenso: { titulo: 'hola', texto: 'chau' } }
titulo: 'hola',
texto: 'chau'
}
}
assert_equal 201, @response.status assert_equal 201, @response.status
@ -80,9 +79,10 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
end end
test 'se pueden borrar si están vacíos' do test 'se pueden borrar si están vacíos' do
consenso = create :consenso consenso = create :consenso, barca: @barca
delete consenso_url(consenso), as: :json, headers: @auth delete barca_consenso_url(@barca, consenso),
as: :json, headers: @auth
assert_equal 200, @response.status assert_equal 200, @response.status
@ -91,10 +91,11 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest
end end
test 'no se pueden borrar si no están vacíos' do test 'no se pueden borrar si no están vacíos' do
consenso = create :consenso consenso = create :consenso, barca: @barca
create :posicion, consenso: consenso create :posicion, consenso: consenso
delete consenso_url(consenso), as: :json, headers: @auth delete barca_consenso_url(@barca, consenso),
as: :json, headers: @auth
assert_equal 422, @response.status assert_equal 422, @response.status
end end

View file

@ -4,22 +4,19 @@ require 'test_helper'
class PosicionesControllerTest < ActionDispatch::IntegrationTest class PosicionesControllerTest < ActionDispatch::IntegrationTest
setup do setup do
@barca = create :barca
@pirata = create :pirata @pirata = create :pirata
@auth = { Authorization: ActionController::HttpAuthentication::Basic @auth = { Authorization: ActionController::HttpAuthentication::Basic
.encode_credentials(@pirata.email, @pirata.password) } .encode_credentials(@pirata.email, @pirata.password) }
end end
test 'se pueden crear' do test 'se pueden crear' do
consenso = create :consenso consenso = create :consenso, barca: @barca
estado = Posicion::ESTADOS.sample estado = Posicion::ESTADOS.sample
post consenso_posiciones_url(consenso), as: :json, headers: @auth, post barca_consenso_posiciones_url(@barca, consenso),
params: { as: :json, headers: @auth,
posicion: { params: { posicion: { estado: estado, comentario: 'porque me place' } }
estado: estado,
comentario: 'porque me place'
}
}
assert_equal 201, @response.status assert_equal 201, @response.status

16
test/factories/barca.rb Normal file
View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
FactoryBot.define do
factory :barca do
nombre { SecureRandom.hex }
descripcion { SecureRandom.hex }
transient do
tripulacion { 0 }
end
after :create do |barca, evaluator|
create_list(:tripulacion, evaluator.tripulacion, barca: barca)
end
end
end

View file

@ -2,6 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :consenso do factory :consenso do
barca
pirata pirata
titulo { 'Estamos a favor de la despenalización del aborto' } titulo { 'Estamos a favor de la despenalización del aborto' }
texto { '...' } texto { '...' }

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
FactoryBot.define do
factory :tripulacion do
barca
pirata
end
end

32
test/models/barca_test.rb Normal file
View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
class BarcaTest < ActiveSupport::TestCase
test 'se pueden crear' do
barca = create :barca
assert_equal true, barca.valid?
end
test 'pueden tener tripulacion' do
barca = create :barca, tripulacion: 3
assert_equal 3, barca.tripulaciones.count
assert_equal 3, barca.piratas.count
end
test 'el nombre tiene que ser único' do
create :barca, nombre: 'hola'
barca = build :barca, nombre: 'hola'
assert barca.invalid?
end
test 'al eliminar la barca se elimina su tripulación' do
barca = create :barca, tripulacion: 3
assert barca.destroy
assert_equal 3, Pirata.all.count
assert Tripulacion.all.count.zero?
end
end