Please does anyone know how to specify a many-to-many relationship in buffalo models?
gobuffalo many_to_many ...
type Organization struct {
ID int `json:"id" db:"id"`
Users Users `many_to_many:"user_organizations"`
}
type User struct {
ID int `json:"id" db:"id"`
Organizations Organizations `many_to_many:"user_organizations" json:"-"`
}
type UserOrganization struct {
ID int `json:"id" db:"id"`
OrganizationID int `json:"organization_id" db:"organization_id"`
UserID int `json:"user_id" db:"user_id"`
User User `belongs_to:"users"`
Organization Organization `belongs_to:"organizations"`
}
Each of these structs are in their own models/*.go file
https://gobuffalo.io/en/docs/db/relations
Related
I receive this error
controllers/users.go:61:36: user.ID undefined (type models.User has no field or method ID)
when using
var user models.User
...
jwtToken, err := generateJWT(user.ID, user.Username)
The definition of User model:
package models
import "time"
type BaseModel struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel BaseModel `gorm:"embedded"`
Username string `json:"username"`
Password string `json:"password"`
}
Actually I put BaseModel in different file but in the same package with User. Migration works fine as table users have all columns in BaseModel. What is the problem? I use golang 1.18 and latest version of GORM
You have used BaseModel as attribute in your model so even though gorm can very well map it to the table column to access it, you have to use the attribute name
To access you would do
jwtToken, err := generateJWT(user.BaseModel.ID, user.Username)
you could also try this next code to see if it works otherwise the above will work for sure
type BaseModel struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel `gorm:"embedded"`
Username string `json:"username"`
Password string `json:"password"`
}
now you might be able to access it like your original pattern
jwtToken, err := generateJWT(user.ID, user.Username)
type Books_model struct {
// gorm.Model
Book_id string `json:"book_id" gorm:"primarykey"`
Title string `json:"title"`
Author string `json:"author"`
Gender string `json:"gender"`
Publisher string `json:"publisher"`
Country string `json:"country"`
Rating_model Rating_model `gorm:"foreignKey:Books_rating_id;AssociationForeignKey:Books_rating_id"`
// ;AssociationForeignKey:Books_rating_id
Reviews_model Reviews_model `gorm:"foreignKey:Books_model_id;AssociationKey:Books_model_id"`
}
type Rating_model struct {
gorm.Model
Books_rating_id string `json:"books_rating_id" `
`gorm:"foreignKey:book_id;references:Book_id"`
Rating string `json:"rating"`
}
type Reviews_model struct {
gorm.Model
Ret_id string `json:"ret_id"`
Books_model_id string `json:"books_model_id"`
Review string `json:"review"`
}
##############################
My problem is that i have made foreign keys and i have make joins to combine the tables like book id 3 has rating of 4 and review is this, but i am trying no query is working,Gorm is really hard to understand.
tl;dr
How can I dynamize the JSON fields of a struct?
I am using gorm as the ORM. I have my model definition as a struct:
type UserAccessToken struct {
Id uint `gorm:"primaryKey" json:"-"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt gorm.DeletedAt `json:"deletedAt"`
User User `gorm:"constraint:OnDelete:CASCADE" json:"-"`
UserId uint `gorm:"not null" json:"-"`
IpAddress string `gorm:"not null" json:"ipAddress"`
Token string `gorm:"not null" json:"token"`
}
I have multiple endpoints and I want to use different fields of the struct serialized on each endpoint.
For example, on POST /user-access-tokens/ user will be basic authenticated and a new access token will be created and returned on the response. However, on GET /user-access-tokens/ list API endpoint, the response will be a list of the UserAccessTokens, but the Token won't be on the response. And I am planning to create another endpoint only to be used by the administration interface, and all fields will be available there.
There are two I can think of:
Creating a different struct and reading from the database into this struct.
Adding a method like Map(scenario string) to the model struct which will create a map of the struct according to scenario, but in this case, I also need to add function to handle multiple instances of the struct.
What is the recommended way for this?
You can use another struct:
type UserAccessstruct {
Id uint `gorm:"primaryKey" json:"-"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt gorm.DeletedAt `json:"deletedAt"`
User User `gorm:"constraint:OnDelete:CASCADE" json:"-"`
UserId uint `gorm:"not null" json:"-"`
IpAddress string `gorm:"not null" json:"ipAddress"`
}
type UserAccessToken {
UserAccessstruct
Token string `gorm:"not null" json:"token"`
}
func Get() {
var userAccess UserAccessToken
db.Select(selectQuery).First(&userAccess)
return userAccess // Full return
return userAccess.UserAccessstruct // Inner struct without token
}
I am trying to create a rest API with golang. Each time a user is created, I would like to create a 'Profile' which is associated with that user.
My initial thought was to first create the user, and then separately create the profile referencing the user ID and inserting that into the database.
I'm not sure if this kind of thinking aligns with the way go should be used as i'm just starting with the language.
Using below code, I create the user, but cannot create the profile. I receive this error: using unaddressable value
var db *gorm.DB
func GetDB() *gorm.DB {
return db
}
type User struct {
gorm.Model
Email string `gorm:"type:varchar(100);unique_index"`
Password string `json:"password"`
Name string `json:"name"`
Token string `json:"token";sql:"-"`
}
type Profile struct {
gorm.Model
User User `gorm:"foreignkey:UserRefer"` // use UserRefer as foreign key
UserRefer uint
FirstName string `gorm:"default:'John'"`
LastName string `gorm:"default:'Doe'"`
Description string `gorm:"default:'Mysterious'"`
}
func (user *User) Create() (map[string]interface{}) {
if resp, ok := user.Validate(); !ok {
return resp
}
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
user.Password = string(hashedPassword)
GetDB().Create(user)
profile := Profile{}
profile.UserRefer = user.ID
GetDB().Create(profile)
if user.ID <= 0 {
return u.Message(false, "Failed to create account, connection error.")
}
response := u.Message(true, "Account has been created")
response["user"] = user
return response
}
I'm hoping someone will be able to help me understand what is going wrong here?
You should pass a pointer on gorm's Create method to get your model Filled after creation...
GetDB().Create(&profile)
But, as is showed in https://gorm.io/docs/associations.html gorm Auto create the associations.
You can change your models, like so... (I am supposing that User and Profile has a 1..1 relation ok?)
And everything will get done automatically
type User struct {
gorm.Model
Email string `gorm:"type:varchar(100);unique_index"`
Password string `json:"password"`
Name string `json:"name"`
Token string `json:"token";sql:"-"`
Profile Profile
ProfileID uint
}
type Profile struct {
gorm.Model
UserID uint
FirstName string `gorm:"default:'John'"`
LastName string `gorm:"default:'Doe'"`
Description string `gorm:"default:'Mysterious'"`
}
So gorm.Model provides some base properties or fields:
ID uint `json:"-" gorm:"primary_key"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-" sql:"index"`
and you can use it as so
type User struct {
gorm.Model
Name string
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // set field size to 255
}
So when I was working on my Model Controller(s) for delete (or anything where I needed to compare the ID)
This does not work, give me an error:
c.Ctx.DB.Delete(&models.Address{ID: id})
unknown field 'ID' in struct literal of type
github.com/NlaakStudios/PASIT/models".Address
And, this does not work, give me an error:
c.Ctx.DB.Delete(&models.Address{gorm.Model.ID: id})
invalid field name gorm.Model.ID in struct initializer id int
If I remove the gorm.Model and define the field myself in each model ... it works.
type User struct {
ID uint `json:"-" gorm:"primary_key"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-" sql:"index"`
Name string
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // set field size to 255
}
How do I access those four base fields?
You're very close in your last example. You can remove the gorm.Model inheritance from your struct if you want/need (I personally do that for clarity), but to access that value you'd just need to build up your struct a little more. For example...
type Address struct {
gorm.Model
Name string
Email string `gorm:"type:varchar(100);unique_index"`
Role string `gorm:"size:255"` // set field size to 255
}
c.Ctx.DB.Delete(&models.Address{gorm.Model: gorm.Model{ID: id}})
Give that a try and see if that works for you. Alternatively revert to your method without inheriting the gorm.Model
I worked with this: removing package Name 'gorm'
c.Ctx.DB.Delete(&models.Address{Model: gorm.Model{ID: id}})
looks like this is an interesting question - but of category 'selfmade problem':
what about
c.Ctx.DB.Delete(&model.Address{}, id)
then you can keep the benefits (or not - depends on taste) of gorm.Model