adonisjs / core

AdonisJS is a TypeScript-first web framework for building web apps and API servers. It comes with support for testing, modern tooling, an ecosystem of official packages, and more.
https://adonisjs.com
MIT License
16.9k stars 639 forks source link

hasOne is not a function #940

Closed jordykoppen closed 6 years ago

jordykoppen commented 6 years ago

I have an issue with one of my models and using a relation.

User Model:

'use strict'

const Model = use('Model')

class User extends Model {
  static boot () {
    super.boot()
  }

  static get hidden () {
    return ['password', 'created_at', 'updated_at']
  }

  role () {
    return this.hasOne('App/Models/Role', 'role', 'id')
  }
}

module.exports = User

On my user schema I have a foreign key called role

When I try and call this:

async getUser ({ response, auth }) {
    const user = await auth.getUser()
    await user.role().fetch()
    return user
  }

I get the error returned this.hasOne is not a function

Can somebody help me figure out what I'm doing wrong here?

thetutlage commented 6 years ago

I tried the exact code and it works fine. Is there something else that you didn’t shared? Also can you please share the complete error stack?

jordykoppen commented 6 years ago

Thanks for the fast reply. Tomorrow I'll post an update when I'm back at it

jordykoppen commented 6 years ago

Alright, so I did a check and still have the same issue. Let me post all of the related code:

User Schema

this.create('users', table => {
      table.increments()
      table.string('name', 254).notNullable()
      table.string('email', 254).notNullable().unique()
      table.integer('role').unsigned()
      table.string('password', 60).notNullable()
      table.timestamps()
    })

Role Schema

this.create('roles', (table) => {
      table.increments()
      table.string('name', 254).notNullable()
      table.string('label', 254).notNullable()
      table.timestamps()
    })

After, I have a migration that will assign all foreign keys:

this.table('users', (table) => {
      table.foreign('role').references('roles.id').onDelete('SET NULL')
    })

With my migrations covered, the User Model

role () {
    return this.hasOne('App/Models/Role', 'role', 'id')
  }

And finally the function inside UserController I call trough an endpoint

async getUser ({ response, auth }) {
    try {
      const user = await auth.getUser()

      await user.role().fetch()

      return user
    } catch (err) {
      response.send('Missing or invalid JWT token')
    }
  }

Where can I find the complete error stack? The only thing it refers to is the line where this.hasOne is called..

thetutlage commented 6 years ago

Would you mind sharing a repo with the minimum required code to reproduce this issue?

jordykoppen commented 6 years ago

No worries, will do once I'm home

jordykoppen commented 6 years ago

Made a repo with instructions in the README.md https://github.com/jordykoppen/adonis-940-replica

thetutlage commented 6 years ago

Your data attributes has a field called role, which is conflicting with the role property on the model.

Ideally the field name inside the database must be role_id.

But yes, I can improve the error message in this case

jordykoppen commented 6 years ago

Alright, makes sense! Being on this topic, is there any way to

Like:

const user = await User.find(1)
await user.role().fetch()

// Returns
{
  name: 'John',
  role: {
    id: 1,
    name: 'admin'
  },
  ...
}

I only could find an example in the docs about using query().with().fetch() which would then return all the users?

thetutlage commented 6 years ago

Yup, you can read about it here https://adonisjs.com/docs/4.1/relationships#_lazy_eager_loading.

This Eagerloads for that user and attaches it to the user instance.

await user.load('role')
return user.toJSON()
jordykoppen commented 6 years ago

Oops! completely missed that.. :)

Thanks for your time and help 👍

angherq commented 5 years ago

As a suggestion it would be nice to have that tip in the documentation, it may be common to have a column on the DB with the same name as the relationship on the model.
A curious thing, this problem only occurred on my staging server but worked just fine in my local machine.

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.