Make the application multi-tenant based on a wedding model #153

Merged
bustikiller merged 16 commits from wedding-model into main 2024-12-01 10:11:25 +00:00
31 changed files with 273 additions and 100 deletions

View File

@ -20,6 +20,7 @@ gem 'jsonapi-rails'
gem 'rack-cors' gem 'rack-cors'
gem 'react-rails' gem 'react-rails'
gem 'rubytree' gem 'rubytree'
gem 'acts_as_tenant'
group :development, :test do group :development, :test do
gem 'annotaterb' gem 'annotaterb'

View File

@ -72,6 +72,8 @@ GEM
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1) uri (>= 0.13.1)
acts_as_tenant (1.0.1)
rails (>= 6.0)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
annotaterb (4.13.0) annotaterb (4.13.0)
@ -387,6 +389,7 @@ PLATFORMS
x86_64-linux x86_64-linux
DEPENDENCIES DEPENDENCIES
acts_as_tenant
annotaterb annotaterb
bootsnap bootsnap
chroma chroma

View File

@ -1,6 +1,7 @@
# Copyright (C) 2024 Manuel Bustillo # Copyright (C) 2024 Manuel Bustillo
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
before_action :set_tenant
before_action :authenticate_user! before_action :authenticate_user!
after_action :set_csrf_cookie after_action :set_csrf_cookie
@ -29,6 +30,10 @@ class ApplicationController < ActionController::Base
private private
def set_tenant
ActsAsTenant.current_tenant = Wedding.find_by(slug: params[:slug])
end
def development_swagger? def development_swagger?
Rails.env.test? || Rails.env.test? ||
Rails.env.development? && request.headers['referer']&.include?('/api-docs/index.html') Rails.env.development? && request.headers['referer']&.include?('/api-docs/index.html')

View File

@ -3,7 +3,8 @@
class TableSimulatorJob < ApplicationJob class TableSimulatorJob < ApplicationJob
queue_as :default queue_as :default
def perform(*_args) def perform(wedding_id)
ActsAsTenant.with_tenant(Wedding.find(wedding_id)) do
engine = VNS::Engine.new engine = VNS::Engine.new
engine.add_perturbation(Tables::Swap) engine.add_perturbation(Tables::Swap)
@ -21,3 +22,4 @@ class TableSimulatorJob < ApplicationJob
best_solution.save! best_solution.save!
end end
end end
end

View File

@ -10,8 +10,18 @@
# pricing_type :enum default("fixed"), not null # pricing_type :enum default("fixed"), not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# wedding_id :uuid not null
#
# Indexes
#
# index_expenses_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id)
# #
class Expense < ApplicationRecord class Expense < ApplicationRecord
acts_as_tenant :wedding
enum :pricing_type, enum :pricing_type,
fixed: 'fixed', fixed: 'fixed',
per_person: 'per_person' per_person: 'per_person'

View File

@ -12,17 +12,22 @@
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# parent_id :uuid # parent_id :uuid
# wedding_id :uuid not null
# #
# Indexes # Indexes
# #
# index_groups_on_name (name) UNIQUE # index_groups_on_name (name) UNIQUE
# index_groups_on_parent_id (parent_id) # index_groups_on_parent_id (parent_id)
# index_groups_on_wedding_id (wedding_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (parent_id => groups.id) # fk_rails_... (parent_id => groups.id)
# fk_rails_... (wedding_id => weddings.id)
# #
class Group < ApplicationRecord class Group < ApplicationRecord
acts_as_tenant :wedding
validates :name, uniqueness: true validates :name, uniqueness: true
validates :name, :order, presence: true validates :name, :order, presence: true

View File

@ -11,16 +11,20 @@
# 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 not null
# wedding_id :uuid not null
# #
# Indexes # Indexes
# #
# index_guests_on_group_id (group_id) # index_guests_on_group_id (group_id)
# index_guests_on_wedding_id (wedding_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (group_id => groups.id) # fk_rails_... (group_id => groups.id)
# fk_rails_... (wedding_id => weddings.id)
# #
class Guest < ApplicationRecord class Guest < ApplicationRecord
acts_as_tenant :wedding
belongs_to :group belongs_to :group
enum :status, { enum :status, {
@ -45,6 +49,6 @@ class Guest < ApplicationRecord
def recalculate_simulations def recalculate_simulations
TablesArrangement.delete_all TablesArrangement.delete_all
ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new }) ActiveJob.perform_all_later(50.times.map { TableSimulatorJob.new(wedding_id) })
end end
end end

View File

@ -10,18 +10,22 @@
# updated_at :datetime not null # updated_at :datetime not null
# guest_id :uuid not null # guest_id :uuid not null
# tables_arrangement_id :uuid not null # tables_arrangement_id :uuid not null
# wedding_id :uuid not null
# #
# Indexes # Indexes
# #
# index_seats_on_guest_id (guest_id) # index_seats_on_guest_id (guest_id)
# index_seats_on_tables_arrangement_id (tables_arrangement_id) # index_seats_on_tables_arrangement_id (tables_arrangement_id)
# index_seats_on_wedding_id (wedding_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (guest_id => guests.id) # fk_rails_... (guest_id => guests.id)
# fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade # fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade
# fk_rails_... (wedding_id => weddings.id)
# #
class Seat < ApplicationRecord class Seat < ApplicationRecord
acts_as_tenant :wedding
belongs_to :guest belongs_to :guest
belongs_to :table_arrangement belongs_to :table_arrangement
end end

View File

@ -9,8 +9,18 @@
# name :string not null # name :string not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# wedding_id :uuid not null
#
# Indexes
#
# index_tables_arrangements_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id)
# #
class TablesArrangement < ApplicationRecord class TablesArrangement < ApplicationRecord
acts_as_tenant :wedding
has_many :seats has_many :seats
has_many :guests, through: :seats has_many :guests, through: :seats

View File

@ -18,6 +18,7 @@
# unlock_token :string # unlock_token :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# wedding_id :uuid not null
# #
# Indexes # Indexes
# #
@ -25,8 +26,15 @@
# index_users_on_email (email) UNIQUE # index_users_on_email (email) UNIQUE
# index_users_on_reset_password_token (reset_password_token) UNIQUE # index_users_on_reset_password_token (reset_password_token) UNIQUE
# index_users_on_unlock_token (unlock_token) UNIQUE # index_users_on_unlock_token (unlock_token) UNIQUE
# index_users_on_wedding_id (wedding_id)
#
# Foreign Keys
#
# fk_rails_... (wedding_id => weddings.id)
# #
class User < ApplicationRecord class User < ApplicationRecord
acts_as_tenant :wedding
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
:recoverable, :validatable, :confirmable, :lockable :recoverable, :validatable, :confirmable, :lockable
end end

20
app/models/wedding.rb Normal file
View File

@ -0,0 +1,20 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: weddings
#
# id :uuid not null, primary key
# date :date not null
# slug :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_weddings_on_slug (slug) UNIQUE
#
class Wedding < ApplicationRecord
validates :date, presence: true
validates :slug, presence: true, uniqueness: true
end

View File

@ -2,6 +2,7 @@
Rails.application.routes.draw do Rails.application.routes.draw do
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
scope ":slug", constraints: {slug: /[a-z]+/} do
devise_for :users, skip: [:registration, :session, :confirmation] devise_for :users, skip: [:registration, :session, :confirmation]
devise_scope :user do devise_scope :user do
post 'users', to: 'users/registrations#create' post 'users', to: 'users/registrations#create'
@ -12,8 +13,6 @@ 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
mount Rswag::Ui::Engine => '/api-docs'
mount Rswag::Api::Engine => '/api-docs'
resources :groups, only: :index resources :groups, only: :index
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
@ -22,6 +21,11 @@ Rails.application.routes.draw do
get :summary, on: :collection get :summary, on: :collection
end end
resources :tables_arrangements, only: %i[index show] resources :tables_arrangements, only: %i[index show]
end
mount Rswag::Ui::Engine => '/api-docs'
mount Rswag::Api::Engine => '/api-docs'
get 'up' => 'rails/health#show', as: :rails_health_check get 'up' => 'rails/health#show', as: :rails_health_check

View File

@ -0,0 +1,12 @@
# Copyright (C) 2024 Manuel Bustillo
class CreateWeddings < ActiveRecord::Migration[8.0]
def change
create_table :weddings, id: :uuid do |t|
t.string :slug, null: false, index: { unique: true }
t.date :date, null: false
t.timestamps
end
end
end

View File

@ -0,0 +1,9 @@
# Copyright (C) 2024 Manuel Bustillo
class AddWeddingIdToModels < ActiveRecord::Migration[8.0]
def change
[:expenses, :guests, :seats, :tables_arrangements, :groups, :users].each do |table|
add_reference table, :wedding, type: :uuid, null: false, foreign_key: true
end
end
end

28
db/schema.rb generated
View File

@ -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_11_30_095753) do ActiveRecord::Schema[8.0].define(version: 2024_11_30_185731) 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"
@ -26,6 +26,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
t.enum "pricing_type", default: "fixed", null: false, enum_type: "pricing_types" t.enum "pricing_type", default: "fixed", null: false, enum_type: "pricing_types"
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 "wedding_id", null: false
t.index ["wedding_id"], name: "index_expenses_on_wedding_id"
end end
create_table "groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
@ -36,8 +38,10 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.uuid "parent_id" t.uuid "parent_id"
t.string "color" t.string "color"
t.uuid "wedding_id", null: false
t.index ["name"], name: "index_groups_on_name", unique: true t.index ["name"], name: "index_groups_on_name", unique: true
t.index ["parent_id"], name: "index_groups_on_parent_id" t.index ["parent_id"], name: "index_groups_on_parent_id"
t.index ["wedding_id"], name: "index_groups_on_wedding_id"
end end
create_table "guests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "guests", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
@ -47,7 +51,9 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
t.uuid "group_id", null: false t.uuid "group_id", null: false
t.integer "status", default: 0 t.integer "status", default: 0
t.string "name" t.string "name"
t.uuid "wedding_id", null: false
t.index ["group_id"], name: "index_guests_on_group_id" t.index ["group_id"], name: "index_guests_on_group_id"
t.index ["wedding_id"], name: "index_guests_on_wedding_id"
end end
create_table "seats", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "seats", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
@ -56,8 +62,10 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
t.integer "table_number" t.integer "table_number"
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 "wedding_id", null: false
t.index ["guest_id"], name: "index_seats_on_guest_id" t.index ["guest_id"], name: "index_seats_on_guest_id"
t.index ["tables_arrangement_id"], name: "index_seats_on_tables_arrangement_id" t.index ["tables_arrangement_id"], name: "index_seats_on_tables_arrangement_id"
t.index ["wedding_id"], name: "index_seats_on_wedding_id"
end end
create_table "solid_queue_blocked_executions", force: :cascade do |t| create_table "solid_queue_blocked_executions", force: :cascade do |t|
@ -186,6 +194,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
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.string "name", null: false t.string "name", null: false
t.uuid "wedding_id", null: false
t.index ["wedding_id"], name: "index_tables_arrangements_on_wedding_id"
end end
create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
@ -202,20 +212,36 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_30_095753) do
t.datetime "locked_at" t.datetime "locked_at"
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 "wedding_id", null: false
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
t.index ["wedding_id"], name: "index_users_on_wedding_id"
end end
create_table "weddings", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "slug", null: false
t.date "date", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["slug"], name: "index_weddings_on_slug", unique: true
end
add_foreign_key "expenses", "weddings"
add_foreign_key "groups", "groups", column: "parent_id" add_foreign_key "groups", "groups", column: "parent_id"
add_foreign_key "groups", "weddings"
add_foreign_key "guests", "groups" add_foreign_key "guests", "groups"
add_foreign_key "guests", "weddings"
add_foreign_key "seats", "guests" add_foreign_key "seats", "guests"
add_foreign_key "seats", "tables_arrangements", on_delete: :cascade add_foreign_key "seats", "tables_arrangements", on_delete: :cascade
add_foreign_key "seats", "weddings"
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "tables_arrangements", "weddings"
add_foreign_key "users", "weddings"
end end

View File

@ -7,6 +7,10 @@ Expense.delete_all
Guest.delete_all Guest.delete_all
Group.delete_all Group.delete_all
Wedding.delete_all
wedding = Wedding.create!(slug: :default, date: 1.year.from_now)
ActsAsTenant.with_tenant(wedding) do
Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed') Expense.create!(name: 'Photographer', amount: 3000, pricing_type: 'fixed')
Expense.create!(name: 'Country house', amount: 6000, pricing_type: 'fixed') Expense.create!(name: 'Country house', amount: 6000, pricing_type: 'fixed')
Expense.create!(name: 'Catering', amount: 200, pricing_type: 'per_person') Expense.create!(name: 'Catering', amount: 200, pricing_type: 'per_person')
@ -63,7 +67,7 @@ NUMBER_OF_GUESTS.times do
) )
end end
ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new }) ActiveJob.perform_all_later(3.times.map { TableSimulatorJob.new(wedding.id) })
'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) } 'red'.paint.palette.triad(as: :hex).zip(Group.roots).each { |(color, group)| group.update!(color: color.paint.desaturate(40)) }
@ -75,3 +79,4 @@ User.create!(
password: 'supersecretpassword', password: 'supersecretpassword',
password_confirmation: 'supersecretpassword', password_confirmation: 'supersecretpassword',
) )
end

View File

@ -2,6 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :expense do factory :expense do
wedding
sequence(:name) { |i| "Expense #{i}" } sequence(:name) { |i| "Expense #{i}" }
pricing_type { "fixed" } pricing_type { "fixed" }
amount { 100 } amount { 100 }

View File

@ -2,6 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :group do factory :group do
wedding
sequence(:name) { |i| "Group #{i}" } sequence(:name) { |i| "Group #{i}" }
order { 1 } order { 1 }
end end

View File

@ -2,7 +2,8 @@
FactoryBot.define do FactoryBot.define do
factory :guest do factory :guest do
association :group group
wedding
name { Faker::Name.name } name { Faker::Name.name }
phone { Faker::PhoneNumber.cell_phone } phone { Faker::PhoneNumber.cell_phone }

View File

@ -0,0 +1,8 @@
# Copyright (C) 2024 Manuel Bustillo
FactoryBot.define do
factory :tables_arrangement do
wedding
end
end

View File

@ -2,6 +2,6 @@
FactoryBot.define do FactoryBot.define do
factory :user do factory :user do
wedding
end end
end end

View File

@ -0,0 +1,8 @@
# Copyright (C) 2024 Manuel Bustillo
FactoryBot.define do
factory :wedding do
sequence(:slug) { |i| "wedding-#{i}" }
date { 1.year.from_now }
end
end

View File

@ -5,7 +5,7 @@ require 'rails_helper'
RSpec.describe TablesArrangement, type: :model do RSpec.describe TablesArrangement, type: :model do
describe 'callbacks' do describe 'callbacks' do
it 'assigns a name before creation' do it 'assigns a name before creation' do
expect(described_class.create!.name).to be_present expect(create(:tables_arrangement).name).to be_present
end end
end end
end end

View File

@ -0,0 +1,7 @@
# Copyright (C) 2024 Manuel Bustillo
require 'rails_helper'
RSpec.describe Wedding, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -3,10 +3,12 @@
require 'swagger_helper' require 'swagger_helper'
RSpec.describe 'expenses', type: :request do RSpec.describe 'expenses', type: :request do
path '/expenses' do path '/{slug}/expenses' do
get('list expenses') do get('list expenses') do
tags 'Expenses' tags 'Expenses'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
response(200, 'successful') do response(200, 'successful') do
schema type: :array, schema type: :array,
items: { items: {
@ -26,12 +28,13 @@ RSpec.describe 'expenses', type: :request do
end end
end end
path '/expenses/{id}' do path '/{slug}/expenses/{id}' do
patch('update expense') do patch('update expense') do
tags 'Expenses' tags 'Expenses'
consumes 'application/json' consumes 'application/json'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: 'id', in: :path, type: :string, format: :uuid, description: 'id' parameter name: 'id', in: :path, type: :string, format: :uuid, description: 'id'
parameter name: :body, in: :body, schema: { parameter name: :body, in: :body, schema: {
type: :object, type: :object,

View File

@ -3,10 +3,11 @@
require 'swagger_helper' require 'swagger_helper'
RSpec.describe 'groups', type: :request do RSpec.describe 'groups', type: :request do
path '/groups' do path '/{slug}/groups' do
get('list groups') do get('list groups') do
tags 'Groups' tags 'Groups'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
response(200, 'successful') do response(200, 'successful') do
schema type: :array, schema type: :array,
items: { items: {

View File

@ -3,10 +3,11 @@
require 'swagger_helper' require 'swagger_helper'
RSpec.describe 'guests', type: :request do RSpec.describe 'guests', type: :request do
path '/guests' do path '/{slug}/guests' do
get('list guests') do get('list guests') do
tags 'Guests' tags 'Guests'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
response(200, 'successful') do response(200, 'successful') do
schema type: :array, schema type: :array,
items: { items: {
@ -33,6 +34,7 @@ RSpec.describe 'guests', type: :request do
tags 'Guests' tags 'Guests'
consumes 'application/json' consumes 'application/json'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: :body, in: :body, schema: { parameter name: :body, in: :body, schema: {
type: :object, type: :object,
required: %i[guest], required: %i[guest],
@ -55,11 +57,12 @@ RSpec.describe 'guests', type: :request do
end end
end end
path '/guests/{id}' do path '/{slug}/guests/{id}' do
patch('update guest') do patch('update guest') do
tags 'Guests' tags 'Guests'
consumes 'application/json' consumes 'application/json'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: 'id', in: :path, type: :string, format: :uuid parameter name: 'id', in: :path, type: :string, format: :uuid
parameter name: :body, in: :body, schema: { parameter name: :body, in: :body, schema: {
type: :object, type: :object,
@ -85,6 +88,7 @@ RSpec.describe 'guests', type: :request do
delete('delete guest') do delete('delete guest') do
tags 'Guests' tags 'Guests'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: 'id', in: :path, type: :string, format: :uuid parameter name: 'id', in: :path, type: :string, format: :uuid
response_empty_200 response_empty_200

View File

@ -9,5 +9,13 @@ module Swagger
updated_at: SwaggerResponseHelper::TIMESTAMP updated_at: SwaggerResponseHelper::TIMESTAMP
} }
SLUG = {
name: 'slug',
in: :path,
type: :string,
example: :default,
description: 'Wedding slug'
}
end end
end end

View File

@ -4,11 +4,12 @@ require 'swagger_helper'
RSpec.describe 'users/confirmations', type: :request do RSpec.describe 'users/confirmations', type: :request do
path '/users/confirmation' do path '/{slug}/users/confirmation' do
get('confirm user email') do get('confirm user email') do
tags 'Users' tags 'Users'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: :confirmation_token, in: :query, type: :string, required: true parameter name: :confirmation_token, in: :query, type: :string, required: true
response(200, 'confirmed') do response(200, 'confirmed') do

View File

@ -4,12 +4,13 @@ require 'swagger_helper'
RSpec.describe 'users/registrations', type: :request do RSpec.describe 'users/registrations', type: :request do
path '/users' do path '/{slug}/users' do
post('create registration') do post('create registration') do
tags 'Users Registrations' tags 'Users Registrations'
consumes 'application/json' consumes 'application/json'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: :body, in: :body, schema: { parameter name: :body, in: :body, schema: {
type: :object, type: :object,
required: [:user], required: [:user],

View File

@ -4,13 +4,14 @@ require 'swagger_helper'
RSpec.describe 'users/sessions', type: :request do RSpec.describe 'users/sessions', type: :request do
path '/users/sign_in' do path '/{slug}/users/sign_in' do
post('create session') do post('create session') do
tags 'Users Sessions' tags 'Users Sessions'
consumes 'application/json' consumes 'application/json'
produces 'application/json' produces 'application/json'
parameter Swagger::Schema::SLUG
parameter name: :body, in: :body, schema: { parameter name: :body, in: :body, schema: {
type: :object, type: :object,
required: %i[user], required: %i[user],
@ -35,8 +36,8 @@ RSpec.describe 'users/sessions', type: :request do
end end
end end
path '/users/sign_out' do path '/{slug}/users/sign_out' do
parameter Swagger::Schema::SLUG
delete('delete session') do delete('delete session') do
tags 'Users Sessions' tags 'Users Sessions'
consumes 'application/json' consumes 'application/json'