Define CUD endpoints for the Groups model #173
1
Gemfile
1
Gemfile
@ -23,6 +23,7 @@ gem 'rubytree'
|
|||||||
gem 'acts_as_tenant'
|
gem 'acts_as_tenant'
|
||||||
gem 'httparty'
|
gem 'httparty'
|
||||||
gem 'rswag'
|
gem 'rswag'
|
||||||
|
gem 'pluck_to_hash'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'annotaterb'
|
gem 'annotaterb'
|
||||||
|
@ -222,6 +222,9 @@ GEM
|
|||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
pg (1.5.9)
|
pg (1.5.9)
|
||||||
|
pluck_to_hash (1.0.2)
|
||||||
|
activerecord (>= 4.0.2)
|
||||||
|
activesupport (>= 4.0.2)
|
||||||
pry (0.15.0)
|
pry (0.15.0)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
@ -413,6 +416,7 @@ DEPENDENCIES
|
|||||||
license_finder
|
license_finder
|
||||||
money
|
money
|
||||||
pg (~> 1.1)
|
pg (~> 1.1)
|
||||||
|
pluck_to_hash
|
||||||
pry
|
pry
|
||||||
puma (>= 5.0)
|
puma (>= 5.0)
|
||||||
rack-cors
|
rack-cors
|
||||||
|
@ -4,4 +4,30 @@ class GroupsController < ApplicationController
|
|||||||
def index
|
def index
|
||||||
render json: Groups::SummaryQuery.new.call.as_json
|
render json: Groups::SummaryQuery.new.call.as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
group = Group.create!(**group_params, parent:)
|
||||||
|
render json: group.as_json(only: %i[id name icon color parent_id]), status: :created
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
group = Group.find(params[:id])
|
||||||
|
group.update!(**group_params, parent:)
|
||||||
|
render json: group.as_json(only: %i[id name icon color parent_id]), status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
Group.find(params[:id]).destroy!
|
||||||
|
render json: {}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def parent
|
||||||
|
params[:group][:parent_id].present? ? Group.find(params[:group][:parent_id]) : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_params
|
||||||
|
params.expect(group: [:name, :icon, :color])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -38,7 +38,7 @@ class Group < ApplicationRecord
|
|||||||
|
|
||||||
scope :roots, -> { where(parent_id: nil) }
|
scope :roots, -> { where(parent_id: nil) }
|
||||||
|
|
||||||
has_many :guests
|
has_many :guests, dependent: :nullify
|
||||||
|
|
||||||
def colorize_children(generation = 1)
|
def colorize_children(generation = 1)
|
||||||
derived_colors = generation == 1 ? color.paint.palette.analogous(size: children.count) : color.paint.palette.decreasing_saturation
|
derived_colors = generation == 1 ? color.paint.palette.analogous(size: children.count) : color.paint.palette.decreasing_saturation
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
# status :integer default("considered")
|
# status :integer default("considered")
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# group_id :uuid not null
|
# group_id :uuid
|
||||||
# wedding_id :uuid not null
|
# wedding_id :uuid not null
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
|
@ -3,29 +3,19 @@
|
|||||||
module Groups
|
module Groups
|
||||||
class SummaryQuery
|
class SummaryQuery
|
||||||
def call
|
def call
|
||||||
ActiveRecord::Base.connection.execute(query).to_a
|
Group.left_joins(:guests).group(:id).pluck_to_hash(
|
||||||
end
|
:id,
|
||||||
|
:name,
|
||||||
private
|
:icon,
|
||||||
|
:parent_id,
|
||||||
def query
|
:color,
|
||||||
<<~SQL.squish
|
Arel.sql('count(*) filter (where status IS NOT NULL) as total'),
|
||||||
SELECT
|
Arel.sql('count(*) filter (where status = 0) as considered'),
|
||||||
groups.id,
|
Arel.sql('count(*) filter (where status = 10) as invited'),
|
||||||
groups.name,
|
Arel.sql('count(*) filter (where status = 20) as confirmed'),
|
||||||
groups.icon,
|
Arel.sql('count(*) filter (where status = 30) as declined'),
|
||||||
groups.parent_id,
|
Arel.sql('count(*) filter (where status = 40) as tentative'),
|
||||||
groups.color,
|
)
|
||||||
count(*) filter (where status IS NOT NULL) as total,
|
|
||||||
count(*) filter (where status = 0) as considered,
|
|
||||||
count(*) filter (where status = 10) as invited,
|
|
||||||
count(*) filter (where status = 20) as confirmed,
|
|
||||||
count(*) filter (where status = 30) as declined,
|
|
||||||
count(*) filter (where status = 40) as tentative
|
|
||||||
FROM groups
|
|
||||||
LEFT JOIN guests on groups.id = guests.group_id
|
|
||||||
GROUP BY groups.id
|
|
||||||
SQL
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -13,7 +13,7 @@ Rails.application.routes.draw do
|
|||||||
get '/users/confirmation', to: 'users/confirmations#show', as: :confirmation
|
get '/users/confirmation', to: 'users/confirmations#show', as: :confirmation
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :groups, only: :index
|
resources :groups, only: %i[index create update destroy]
|
||||||
resources :guests, only: %i[index create update destroy] do
|
resources :guests, only: %i[index create update destroy] do
|
||||||
post :bulk_update, on: :collection
|
post :bulk_update, on: :collection
|
||||||
end
|
end
|
||||||
|
7
db/migrate/20241208102932_allow_ungrouped_guests.rb
Normal file
7
db/migrate/20241208102932_allow_ungrouped_guests.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Copyright (C) 2024 Manuel Bustillo
|
||||||
|
|
||||||
|
class AllowUngroupedGuests < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
change_column_null :guests, :group_id, true
|
||||||
|
end
|
||||||
|
end
|
4
db/schema.rb
generated
4
db/schema.rb
generated
@ -12,7 +12,7 @@
|
|||||||
#
|
#
|
||||||
# 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[8.0].define(version: 2024_12_07_112305) do
|
ActiveRecord::Schema[8.0].define(version: 2024_12_08_102932) 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 "pg_catalog.plpgsql"
|
enable_extension "pg_catalog.plpgsql"
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ ActiveRecord::Schema[8.0].define(version: 2024_12_07_112305) do
|
|||||||
t.string "phone"
|
t.string "phone"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.uuid "group_id", null: false
|
t.uuid "group_id"
|
||||||
t.integer "status", default: 0
|
t.integer "status", default: 0
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.uuid "wedding_id", null: false
|
t.uuid "wedding_id", null: false
|
||||||
|
@ -31,5 +31,72 @@ RSpec.describe 'groups', type: :request do
|
|||||||
end
|
end
|
||||||
regular_api_responses
|
regular_api_responses
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post('create group') do
|
||||||
|
tags 'Groups'
|
||||||
|
consumes 'application/json'
|
||||||
|
produces 'application/json'
|
||||||
|
parameter Swagger::Schema::SLUG
|
||||||
|
parameter name: :body, in: :body, schema: {
|
||||||
|
type: :object,
|
||||||
|
required: %i[group],
|
||||||
|
properties: {
|
||||||
|
group: {
|
||||||
|
type: :object,
|
||||||
|
required: %i[name],
|
||||||
|
properties: Swagger::Schema::GROUP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response(201, 'created') do
|
||||||
|
schema type: :object, properties: {
|
||||||
|
id: { type: :string, format: :uuid, required: true },
|
||||||
|
**Swagger::Schema::GROUP
|
||||||
|
}
|
||||||
|
|
||||||
|
xit
|
||||||
|
end
|
||||||
|
regular_api_responses
|
||||||
|
end
|
||||||
|
|
||||||
|
path '/{slug}/groups/{id}' do
|
||||||
|
put('update group') do
|
||||||
|
tags 'Groups'
|
||||||
|
consumes 'application/json'
|
||||||
|
produces 'application/json'
|
||||||
|
parameter Swagger::Schema::SLUG
|
||||||
|
parameter name: :id, in: :path, type: :string, format: :uuid
|
||||||
|
parameter name: :body, in: :body, schema: {
|
||||||
|
type: :object,
|
||||||
|
required: %i[group],
|
||||||
|
properties: {
|
||||||
|
group: {
|
||||||
|
type: :object,
|
||||||
|
required: %i[name],
|
||||||
|
properties: Swagger::Schema::GROUP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response(200, 'updated') do
|
||||||
|
schema type: :object, properties: {
|
||||||
|
id: { type: :string, format: :uuid, required: true },
|
||||||
|
**Swagger::Schema::GROUP
|
||||||
|
}
|
||||||
|
|
||||||
|
xit
|
||||||
|
end
|
||||||
|
regular_api_responses
|
||||||
|
end
|
||||||
|
|
||||||
|
delete('delete group') do
|
||||||
|
tags 'Groups'
|
||||||
|
produces 'application/json'
|
||||||
|
parameter Swagger::Schema::SLUG
|
||||||
|
parameter name: :id, in: :path, type: :string, format: :uuid
|
||||||
|
|
||||||
|
response_empty_200
|
||||||
|
regular_api_responses
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,10 +4,16 @@ module Swagger
|
|||||||
module Schema
|
module Schema
|
||||||
USER = {
|
USER = {
|
||||||
id: { type: :string, format: :uuid },
|
id: { type: :string, format: :uuid },
|
||||||
email: { type: :string, format: :email },
|
email: { type: :string, format: :email },
|
||||||
created_at: SwaggerResponseHelper::TIMESTAMP,
|
created_at: SwaggerResponseHelper::TIMESTAMP,
|
||||||
updated_at: SwaggerResponseHelper::TIMESTAMP
|
updated_at: SwaggerResponseHelper::TIMESTAMP
|
||||||
|
}
|
||||||
|
|
||||||
|
GROUP = {
|
||||||
|
name: { type: :string },
|
||||||
|
icon: { type: :string, example: 'pi pi-crown', description: 'The CSS classes used by the icon' },
|
||||||
|
parent_id: { type: :string, format: :uuid },
|
||||||
|
color: { type: :string, pattern: '^#(?:[0-9a-fA-F]{3}){1,2}$' }
|
||||||
}
|
}
|
||||||
|
|
||||||
SLUG = {
|
SLUG = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user