diff --git a/app/controllers/consensos_controller.rb b/app/controllers/consensos_controller.rb index 919161a..50be7af 100644 --- a/app/controllers/consensos_controller.rb +++ b/app/controllers/consensos_controller.rb @@ -6,17 +6,18 @@ class ConsensosController < ApplicationController # Para cualquier acción necesitamos autenticación 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 ] def index - @consensos = Consenso.all.order(:created_at, :desc) + @consensos = @barca.consensos.order(:created_at, :desc) end - # GET /consensos/:id + # GET /barcas/:barca_id/consensos/:id # # Podemos ver uno solo sabiendo su ID # @@ -26,13 +27,13 @@ class ConsensosController < ApplicationController # pirata: @pirata, # posiciones: [] } def show - @consenso = Consenso.find(params[:id]) + @consenso = @barca.consensos.find(params[:id]) return if @consenso render json: {}, status: :not_found end - # POST /consensos + # POST /barcas/:barca_id/consensos # # Podemos crear uno, enviando un hash con todas las propiedades # @@ -42,8 +43,8 @@ class ConsensosController < ApplicationController # pirata: @pirata, # posiciones: [] } def create - @consenso = current_pirata.consensos - .new(params.require(:consenso).permit(:titulo, :texto)) + @consenso = current_pirata.consensos.new(consenso_params) + @consenso.barca = @barca if @consenso.save render status: :created @@ -53,7 +54,7 @@ class ConsensosController < ApplicationController end end - # DELETE /consensos/:id + # DELETE /barcas/:barca_id/consensos/:id # # Eliminar un consenso, solo si no tiene posiciones! # @@ -63,7 +64,7 @@ class ConsensosController < ApplicationController # posiciones: [] } def destroy begin - @consenso = Consenso.find(params[:id]) + @consenso = @barca.consensos.find(params[:id]) rescue ActiveRecord::RecordNotFound render json: {}, status: :not_found return @@ -75,4 +76,16 @@ class ConsensosController < ApplicationController render json: {}, status: :unprocessable_entity 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 diff --git a/app/controllers/posiciones_controller.rb b/app/controllers/posiciones_controller.rb index e733536..aff68d7 100644 --- a/app/controllers/posiciones_controller.rb +++ b/app/controllers/posiciones_controller.rb @@ -8,8 +8,9 @@ class PosicionesController < ApplicationController # Necesitamos autenticarnos 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 # @@ -18,7 +19,7 @@ class PosicionesController < ApplicationController # @return [Hash] { id: @int, estado: @string, comentario: @string, # pirata: @pirata } def create - @consenso = Consenso.find(params[:consenso_id]) + @consenso = @barca.consensos.find(params[:consenso_id]) @posicion = @consenso.try(:posiciones).try(:build, posicion_params) @posicion.try(:pirata=, current_pirata) @@ -35,4 +36,8 @@ class PosicionesController < ApplicationController def posicion_params params.require(:posicion).permit(:estado, :comentario) end + + def find_barca! + @barca = Barca.find(params[:barca_id]) + end end diff --git a/app/models/barca.rb b/app/models/barca.rb new file mode 100644 index 0000000..1e9e494 --- /dev/null +++ b/app/models/barca.rb @@ -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 diff --git a/app/models/consenso.rb b/app/models/consenso.rb index fe1a255..9decdfc 100644 --- a/app/models/consenso.rb +++ b/app/models/consenso.rb @@ -7,4 +7,6 @@ class Consenso < ApplicationRecord belongs_to :pirata # Agrupa muchas posiciones has_many :posiciones + # Pertenece a una barca + belongs_to :barca end diff --git a/app/models/pirata.rb b/app/models/pirata.rb index 9b929cd..638096a 100644 --- a/app/models/pirata.rb +++ b/app/models/pirata.rb @@ -7,6 +7,10 @@ class Pirata < ApplicationRecord # Y tener posiciones has_many :posiciones + # Puede participar en barcas + has_many :tripulaciones + has_many :barcas, through: :tripulaciones + # Y además una contraseña segura :P has_secure_password # Una por correo diff --git a/app/models/tripulacion.rb b/app/models/tripulacion.rb new file mode 100644 index 0000000..d80346d --- /dev/null +++ b/app/models/tripulacion.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# La tripulación de una barca +class Tripulacion < ApplicationRecord + belongs_to :barca + belongs_to :pirata +end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 2a1969f..d3815eb 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -10,6 +10,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.singular 'posiciones', 'posicion' inflect.plural 'pirata', 'piratas' inflect.singular 'piratas', 'pirata' + inflect.plural 'tripulacion', 'tripulaciones' + inflect.singular 'tripulaciones', 'tripulacion' end # These inflection rules are supported but not enabled by default: diff --git a/config/routes.rb b/config/routes.rb index ad12fb9..c3f761f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,9 +4,12 @@ Rails.application.routes.draw do get '/piratas/yo', to: 'piratas#yo' # No queremos un índice de piratas resources :piratas, only: %i[create] - # Podemos crear consensos pero no modificarlos - resources :consensos, only: %i[index show create destroy] do - # Y solo le podemos agregar posiciones - resources :posiciones, only: %i[create] + # Podemos crear barcas y dentro de ellas consensos + resources :barcas, only: %i[index show create update destroy] do + # Podemos crear consensos pero no modificarlos + resources :consensos, only: %i[index show create destroy] do + # Y solo le podemos agregar posiciones + resources :posiciones, only: %i[create] + end end end diff --git a/db/migrate/20190803152627_create_barcas.rb b/db/migrate/20190803152627_create_barcas.rb new file mode 100644 index 0000000..a1eab37 --- /dev/null +++ b/db/migrate/20190803152627_create_barcas.rb @@ -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 diff --git a/db/migrate/20190803152706_create_tripulaciones.rb b/db/migrate/20190803152706_create_tripulaciones.rb new file mode 100644 index 0000000..0b982c1 --- /dev/null +++ b/db/migrate/20190803152706_create_tripulaciones.rb @@ -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 diff --git a/db/migrate/20190803152853_add_barca_to_consenso.rb b/db/migrate/20190803152853_add_barca_to_consenso.rb new file mode 100644 index 0000000..a51fc9b --- /dev/null +++ b/db/migrate/20190803152853_add_barca_to_consenso.rb @@ -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 diff --git a/db/migrate/20190803154551_asamblea_general.rb b/db/migrate/20190803154551_asamblea_general.rb new file mode 100644 index 0000000..33e8cc2 --- /dev/null +++ b/db/migrate/20190803154551_asamblea_general.rb @@ -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 diff --git a/test/controllers/consensos_controller_test.rb b/test/controllers/consensos_controller_test.rb index bb29b72..5f6974b 100644 --- a/test/controllers/consensos_controller_test.rb +++ b/test/controllers/consensos_controller_test.rb @@ -2,6 +2,7 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest setup do + @barca = create :barca @pirata = create :pirata @auth = { Authorization: ActionController::HttpAuthentication::Basic .encode_credentials(@pirata.email, @pirata.password) } @@ -9,10 +10,10 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest test 'se pueden mostrar' do 2.times do - create :consenso + create :consenso, barca: @barca end - get consensos_url, as: :json, headers: @auth + get barca_consensos_url(@barca), as: :json, headers: @auth body = JSON.parse(@response.body) assert_equal 200, @response.status @@ -21,7 +22,7 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest test 'al mostrar solo se ven las posiciones resumidas' do 2.times do - consenso = create :consenso + consenso = create :consenso, barca: @barca pirata = create :pirata 3.times do @@ -29,7 +30,7 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest end end - get consensos_url, as: :json, headers: @auth + get barca_consensos_url(@barca), as: :json, headers: @auth body = JSON.parse(@response.body) body['consensos'].each do |consenso| @@ -40,7 +41,9 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest test 'se puede ver uno solo' do 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) assert_equal 200, @response.status @@ -49,26 +52,22 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest end test 'al ver uno solo se ve todo el historial de posiciones' do - consenso = create :consenso + consenso = create :consenso, barca: @barca pirata = create :pirata 3.times do create :posicion, consenso: consenso, pirata: pirata end - get consenso_url(consenso), as: :json, headers: @auth + get barca_consenso_url(@barca, consenso), as: :json, headers: @auth body = JSON.parse(@response.body) assert_equal 3, body['posiciones'].size end test 'se pueden crear' do - post consensos_url, as: :json, headers: @auth, params: { - consenso: { - titulo: 'hola', - texto: 'chau' - } - } + post barca_consensos_url(@barca), as: :json, headers: @auth, + params: { consenso: { titulo: 'hola', texto: 'chau' } } assert_equal 201, @response.status @@ -80,9 +79,10 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest end 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 @@ -91,10 +91,11 @@ class ConsensosControllerTest < ActionDispatch::IntegrationTest end test 'no se pueden borrar si no están vacíos' do - consenso = create :consenso + consenso = create :consenso, barca: @barca 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 end diff --git a/test/controllers/posiciones_controller_test.rb b/test/controllers/posiciones_controller_test.rb index 1bd0de3..c937f4e 100644 --- a/test/controllers/posiciones_controller_test.rb +++ b/test/controllers/posiciones_controller_test.rb @@ -4,22 +4,19 @@ require 'test_helper' class PosicionesControllerTest < ActionDispatch::IntegrationTest setup do + @barca = create :barca @pirata = create :pirata @auth = { Authorization: ActionController::HttpAuthentication::Basic .encode_credentials(@pirata.email, @pirata.password) } end test 'se pueden crear' do - consenso = create :consenso + consenso = create :consenso, barca: @barca estado = Posicion::ESTADOS.sample - post consenso_posiciones_url(consenso), as: :json, headers: @auth, - params: { - posicion: { - estado: estado, - comentario: 'porque me place' - } - } + post barca_consenso_posiciones_url(@barca, consenso), + as: :json, headers: @auth, + params: { posicion: { estado: estado, comentario: 'porque me place' } } assert_equal 201, @response.status diff --git a/test/factories/barca.rb b/test/factories/barca.rb new file mode 100644 index 0000000..be283e0 --- /dev/null +++ b/test/factories/barca.rb @@ -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 diff --git a/test/factories/consensos.rb b/test/factories/consensos.rb index 62582de..83c058f 100644 --- a/test/factories/consensos.rb +++ b/test/factories/consensos.rb @@ -2,6 +2,7 @@ FactoryBot.define do factory :consenso do + barca pirata titulo { 'Estamos a favor de la despenalización del aborto' } texto { '...' } diff --git a/test/factories/tripulacion.rb b/test/factories/tripulacion.rb new file mode 100644 index 0000000..d0b84c5 --- /dev/null +++ b/test/factories/tripulacion.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :tripulacion do + barca + pirata + end +end diff --git a/test/models/barca_test.rb b/test/models/barca_test.rb new file mode 100644 index 0000000..5292d29 --- /dev/null +++ b/test/models/barca_test.rb @@ -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