简体   繁体   中英

Unsure how to save to database with foreign key in AdonisJs

Summary

I'm creating a photography app to help photographers keep track of their clients. This is my first project using Adonis.JS and I really enjoy it so far, but been stuck on this problem for a while and can't find an answer anywhere. I'll share my Models, Controllers, and Migrations (possibly not creating the relationships right, been awhile since I've done any back-end work)

Workflow: A User has many clients, a client has many services Need to be able to get the services from the user.

What I've Tried

When saving in my ServiceController I've tried things like:

const user = await auth.getUser();

service.fill({
   name,
   price,
   quantity,
   due_date
});

await user.clients().services().save(service);

return service;

but sadly I get a 500 error reading: "user.clients(...).services is not a function" which does make sense, just not sure how else to go about it.

One way I had working was:

const clients = await Database.table('clients').select('*').where('user_id', user.id);

await Database.table('services')
   .insert({
      name,
      price,
      quantity,
      due_date: dueDate,
      client_id: clients[0].id
   });

return service;

I just didn't feel like that solution was right, it felt kind of hacky given that Adonis gives Lucid, and I'm not sure; but I feel like that query will cause issues at some point.

Models

User Model

class User extends Model {
   clients() {
      return this.hasMany('App/Models/Client');
   }
}

Client Model

class Client extends Model {
   users() {
      return this.belongsToMany('App/Models/User');
   }

   services() {
      return this.hasMany('App/Model/Service');
   }
}

Service Model

class Service extends Model {
   client() {
      return this.belongsTo('App/Models/Client');
   }
}

Controllers

Service Controller

  async store ({ auth, request, response }) {
    // Get Authenticated user
    const user = await auth.getUser();

    // Retrieve new service from payload
    const { name, price, quantity, dueDate } = request.all();

    const service = new Service();

    service.fill({
      name,
      price,
      quantity,
      due_date: dueDate
    });

    await user.clients().services().save(service);

    return service;
  }

Client Controller

    // Get Authenticated user
    const user = await auth.getUser();

    // Retrieve new client from payload
    const { name, email, address, phoneNumber } = request.all();

    const client = new Client();

    client.fill({
      name,
      email,
      address,
      phone_number: phoneNumber
    });

    await user.clients().save(client);

    return client;

Migrations

Service Schema

class ServiceSchema extends Schema {
  up () {
    this.create('services', (table) => {
      table.increments();
      table.string('name', 255).notNullable();
      table.integer('price', 25).notNullable();
      table.integer('quantity', 25).notNullable().defaultTo(1);
      table.date('due_date', 100).notNullable();
      table.boolean('paid').notNullable().defaultTo(false);

      table.integer('client_id', 25).unsigned().references('id').inTable('clients');
      table.timestamps();
    });
  }

  down () {
    this.drop('services');
  }
}

Client Schema

class ClientSchema extends Schema {
  up () {
    this.create('clients', (table) => {
      table.increments();
      table.string('name', 255).notNullable();
      table.string('email', 255).notNullable();
      table.string('address', 255).notNullable();
      table.string('phone_number', 25).notNullable();

      table.integer('user_id', 25).unsigned().references('id').inTable('users');
      table.timestamps();
    });
  }

  down () {
    this.drop('clients');
  }
}

User Schema

class UserSchema extends Schema {
  up () {
    this.create('users', (table) => {
      table.increments()
      table.string('first_name', 80).notNullable();
      table.string('last_name', 80).notNullable();
      table.string('email', 254).notNullable().unique();
      table.string('password', 60).notNullable();
      table.timestamps();
    });
  }

  down () {
    this.drop('users');
  }
}

Expected output

I want my tables to end up looking like this if possible:

Users Table

| id | first_name | last_name | email | password | created_at | updated_at |

Clients Table

| id | name | email | address | phone_number | user_id | created_at | updated_at |

Services Table

| id | name | quantity | due_date | paid | client_id | created_at | updated_at |

and I need a way to save to services with a reference to the client ID. I was hoping to do this with Lucid, but if that's not applicable here that's fine. Just wanting that consistency.

I ended up deciding that I should probably just pass the clientId in through the body.

Service Controller:

  async store ({ auth, request, response }) {
    // Get Authenticated user
    const user = await auth.getUser();

    // Retrieve new service from payload
    const { name, price, quantity, dueDate, clientId } = request.all();

    const service = await Service.create({
      name,
      price,
      quantity,
      due_date: dueDate,
      client_id: clientId
    });

    return response.status(200).send(service);
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM