W
Wasp4mo ago
scorpil

Creating a record during user sign up

Is there a way to create an additional database record when user signs up? I know about additionalFields, but it seems to only work with simple fields. What I'm looking for is a little bit different: I am trying to add simple multitenancy to the application, so I want to add "Company Name" field to the sign up form, then create a Tenant record in the database and link user to Tenant. It would be possible to record company name on user object, then create Tenant after first log in, but it seems hacky... Is there some hook I can call pre/after User creation?
4 Replies
kapa.ai
kapa.ai4mo ago
Hi @scorpil. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, there are a couple of approaches you can use to create a Tenant record during user signup in Wasp. Option 1: Custom Signup Action The most flexible approach is to create a custom signup action where you have full control over the signup process:
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidUsername,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
} from 'wasp/server/auth'

export const signup = async (args, { entities: { User, Tenant } }) => {
ensureValidUsername(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
// Create the tenant first
const tenant = await Tenant.create({
data: {
name: args.companyName
}
})

const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})

// Create user and link to tenant
await createUser(
providerId,
providerData,
{
tenantId: tenant.id
},
)
} catch (e) {
return {
success: false,
message: e.message,
}
}

return {
success: true,
message: 'User created successfully',
}
}
import {
ensurePasswordIsPresent,
ensureValidPassword,
ensureValidUsername,
createProviderId,
sanitizeAndSerializeProviderData,
createUser,
} from 'wasp/server/auth'

export const signup = async (args, { entities: { User, Tenant } }) => {
ensureValidUsername(args)
ensurePasswordIsPresent(args)
ensureValidPassword(args)

try {
// Create the tenant first
const tenant = await Tenant.create({
data: {
name: args.companyName
}
})

const providerId = createProviderId('username', args.username)
const providerData = await sanitizeAndSerializeProviderData({
hashedPassword: args.password,
})

// Create user and link to tenant
await createUser(
providerId,
providerData,
{
tenantId: tenant.id
},
)
} catch (e) {
return {
success: false,
message: e.message,
}
}

return {
success: true,
message: 'User created successfully',
}
}
You would define this action in your main.wasp file:
action customSignup {
fn: import { signup } from "@src/auth/signup.js",
entities: [User, Tenant]
}
action customSignup {
fn: import { signup } from "@src/auth/signup.js",
entities: [User, Tenant]
}
This approach gives you complete control over the signup process, allowing you to create the Tenant first and then link it to the User during creation. Learn more about custom signup actions. Option 2: userSignupFields with Custom Logic If you prefer to use Wasp's built-in signup form, you can use the userSignupFields feature with some custom logic:
import { defineUserSignupFields } from 'wasp/server/auth'

export const userSignupFields = defineUserSignupFields({
tenantId: async (data, context) => {
// Create a new tenant
const tenant = await context.entities.Tenant.create({
data: {
name: data.companyName
}
})
// Return the tenant ID to be saved on the user
return tenant.id
}
})
import { defineUserSignupFields } from 'wasp/server/auth'

export const userSignupFields = defineUserSignupFields({
tenantId: async (data, context) => {
// Create a new tenant
const tenant = await context.entities.Tenant.create({
data: {
name: data.companyName
}
})
// Return the tenant ID to be saved on the user
return tenant.id
}
})
You would need to define this in your main.wasp file:
auth: {
userEntity: User,
methods: {
usernameAndPassword: {
userSignupFields: import { userSignupFields } from "@src/auth/signup",
},
},
onAuthFailedRedirectTo: "/login",
},
auth: {
userEntity: User,
methods: {
usernameAndPassword: {
userSignupFields: import { userSignupFields } from "@src/auth/signup",
},
},
onAuthFailedRedirectTo: "/login",
},
This approach leverages Wasp's built-in signup process while allowing you to create related records during signup. Learn more about userSignupFields. Both approaches allow you to create a Tenant record and link it to the User during signup, but the custom signup action gives you more control over the entire process. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @scorpil, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
genyus
genyus4mo ago
You may also want to check out this multi-tenancy schema created by another community user: https://discord.com/channels/686873244791210014/1215047437929160724
scorpil
scorpilOP4mo ago
Very cool @genyus, thanks. I don't need Team level, but will probably incorporate RBAC tables at some point.
Filip
Filip4mo ago
Hey @scorpil, the bot gave an overcomplicated answer.
Is there some hook I can call pre/after User creation?
Wasp has exactly this, it's called the onAfterSignup hook. Thanks for linking the thread @genyus

Did you find this page helpful?