I'm trying to build a simple CRUD blog with Golang, Gin and GORM. However, when I wanted to update the blog content, the following error was triggered:
reflect: call of reflect.Value.SetString on uint Value
/usr/local/go/src/reflect/value.go:223 (0x10bfb25)
flag.mustBe: panic(&ValueError{methodName(), f.kind()})
/usr/local/go/src/reflect/value.go:2292 (0x10bfaa3)
Value.SetString: v.mustBe(String)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/schema/field.go:771 (0x144fcfc)
(*Field).setupValuerAndSetter.func11: field.ReflectValueOf(ctx, value).SetString(data)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:144 (0x14b7d9a)
ConvertToAssignments.func2: field.Set(stmt.Context, stmt.ReflectValue, value)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:275 (0x14b62fa)
ConvertToAssignments: assignValue(field, value)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:73 (0x14b4fe4)
Update.func1: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
/Users/sam/go/pkg/mod/gorm.io/[email protected]/callbacks.go:130 (0x146d632)
(*processor).Execute: f(db)
/Users/sam/go/pkg/mod/gorm.io/[email protected]/finisher_api.go:372 (0x1476811)
(*DB).Updates: return tx.callbacks.Update().Execute(tx)
/Volumes/Data/Develop/Go/go-blog/controllers/blog.go:65 (0x1693364)
UpdateBlog: models.DB.Model(&blog).Updates(input)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x168a121)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:99 (0x168a10c)
CustomRecoveryWithWriter.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1689246)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0x1689229)
LoggerWithConfig.func1: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1688310)
(*Context).Next: c.handlers[c.index](c)
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:555 (0x1687f78)
(*Engine).handleHTTPRequest: c.Next()
/Users/sam/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:511 (0x1687ab1)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2916 (0x129bf5a)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1966 (0x1296f56)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1571 (0x10648a0)
goexit: BYTE $0x90 // NOP
However, when I am following the tutorial, everything was all right. Here's my code:
package controllers
import (
"net/http"
"samzhangjy/go-blog/models"
"github.com/gin-gonic/gin"
)
type CreateBlogInput struct {
Title string `json:"title" binding:"required"`
Content string `json:"content" binding:"required"`
}
func CreateBlog(c *gin.Context) {
var input CreateBlogInput
if err := c.ShouldBindJSON(&input); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
blog := models.Blog{Title: input.Title, Content: input.Content}
models.DB.Create(&blog)
c.JSON(http.StatusOK, gin.H{"data": blog})
}
func FindBlogs(c *gin.Context) {
var blogs []models.Blog
models.DB.Find(&blogs)
c.JSON(http.StatusOK, gin.H{"data": blogs})
}
func FindBlog(c *gin.Context) {
var blog models.Blog
if err := models.DB.First(&blog, "id = ?", c.Param("id")).Error; err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": blog})
}
type UpdateBlogInput struct {
Title string `json:"title"`
Content string `json:"content"`
}
func UpdateBlog(c *gin.Context) {
var blog models.Blog
if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "record not found"})
return
}
var input UpdateBlogInput
if err := c.ShouldBindJSON(&input); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
models.DB.Model(&blog).Updates(input)
c.JSON(http.StatusOK, gin.H{"data": blog})
}
I have read this Stackoverflow question but the answer was not that helpful. When I passed empty data to the controller, everything was doing fine. But if I write something to update in the request body, e.g.:
{ "title": "lorem ipsum" }
It will crash and throw the exception mentioned above.
Thanks in advance!
UPDATE:
My models below:
package models
import "time"
type Blog struct {
ID uint `json:"id" gorm:"primary_key"`
Title string `json:"title"`
Content string `json:"content"`
CreatedAt time.Time `json:"created_at"`
}
CodePudding user response:
It might be because you are using a different struct than models.Blog to update. Could you try the following:
func UpdateBlog(c *gin.Context) {
var blog models.Blog
if err := models.DB.Where("id = ?", c.Param("id")).First(&blog).Error; err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": "record not found"})
return
}
var input UpdateBlogInput
if err := c.ShouldBindJSON(&input); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
updateBlog := models.Blog{Title: input.Title, Content: input.Content}
models.DB.Model(&blog).Updates(&updateBlog)
c.JSON(http.StatusOK, gin.H{"data": updateBlog})
}