GO言語ORMによるデータベース操作（jinzhu）によるDBスコープエラー

※初心者のため、間違いや何かご存じの方がいましたら、教えていただけると助かります。

# 概要
以下のサイトに従って、ginによる認証を実装をしていたところ、
「サインアップ」エンドポイント ユーザー情報登録の項目で、POSTしたら、以下の 500 Internal Server Errorが発生した。

https://go.genzouw.com/2023/03/31/post-331/

main.goは以下
```go
package main

import (
	"jwt-gin/controllers"
	"jwt-gin/models"

	"github.com/gin-gonic/gin"
)

func main(){
	models.ConnectDataBase()
	
	router := gin.Default()

	public := router.Group("/api")

	public.POST("/register", controllers.Register)

	router.Run(":8080")
}
```

setup.goは以下
```go
package models

import(
	"fmt"
	"log"
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"github.com/joho/godotenv"
)

var DB *gorm.DB

func ConnectDataBase(){
	err := godotenv.Load()

	if err != nil {
		log.Fatalf("Error loading .env file")
	}

	driver := os.Getenv("DB_DRIVER")
	dbUser := os.Getenv("DB_USER")
	dbPass := os.Getenv("DB_PASS")
	dbName := os.Getenv("DB_NAME")
	dbHost := os.Getenv("DB_HOST")
	dbPort := os.Getenv("DB_PORT")

	dbURI := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Tokyo", dbHost, dbUser, dbPass, dbName, dbPort)

	fmt.Println(dbURI)
	fmt.Println(driver)

	DB, err := gorm.Open(driver, dbURI)

	if err != nil{
		log.Fatal("Could not connect to the database:", err)
	}

	DB.AutoMigrate(&User{})

}
```

auth.go（ユーザー登録するRegister関数）は以下
```go
package controllers

import (
	"fmt"
	"net/http"
	"jwt-gin/models"
	"github.com/gin-gonic/gin"
)

type RegisterInput struct{
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

func Register(c *gin.Context){
	var input RegisterInput

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	fmt.Printf("%+v\n",input)  //inputの確認

	user := models.User{
		Username: input.Username, Password: input.Password,
	}

	fmt.Printf("%+v\n", user)  //userの確認　← ここは問題なし。

	user, err := user.Save()   //← これが実行されないエラー箇所
	
	fmt.Printf("%+v\n", user)  //userの確認　← これが実行されない。
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data": user.PrepareOutput(),
	})
}
```

user.go（user.Save()の中身）は以下
```go
package models

import (
	"strings"

	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
)

type User struct {
    gorm.Model
    Username string `gorm:"size:255;not null;unique" json:"username"`
    Password string `gorm:"size:255;not null;" json:"password"`
}

func (u User) Save() (User, error) {
    err := DB.Create(&u).Error
    if err != nil {
        return User{}, err
    }
    return u, nil
}

func (u *User) BeforeSave() error {
    hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
    if err != nil {
        return err
    }

    u.Password = string(hashedPassword)

    u.Username = strings.ToLower(u.Username)

    return nil
}

func (u User) PrepareOutput() User {
    u.Password = ""
    return u
}
```


### 環境
windows11
docker-desktop
go 1.22


## エラーメッセージ

```go
//main.goで8080番でサーバー立ち上げ
# go run main.go

[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] POST   /api/register             --> jwt-gin/controllers.Register (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.   
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8080

/*
ここで、http://localhost:8080/api/registerへPOSTリクエスト。bodyには以下のJSON形式
{"username":"admin", "password":"pass"}
*/

2024/09/16 16:07:30 [Recovery] 2024/09/16 - 16:07:30 panic recovered:
POST /api/register HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate, br
Connection: close
Content-Length: 38
Content-Type: application/json
User-Agent: got (https://github.com/sindresorhus/got)


runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:261 (0x4558b7)
        panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:881 (0x455885)
        sigpanic: panicmem()
/go/pkg/mod/github.com/jinzhu/gorm@v1.9.16/main.go:853 (0x74d777)
        (*DB).clone: dialect:           newDialect(s.dialect.GetName(), s.db),
/go/pkg/mod/github.com/jinzhu/gorm@v1.9.16/main.go:204 (0x746e25)
        (*DB).NewScope: dbClone := s.clone()
/go/pkg/mod/github.com/jinzhu/gorm@v1.9.16/main.go:482 (0x74a8c4)
        (*DB).Create: scope := s.NewScope(value)
/app/jwt-gin/models/user.go:17 (0x9719eb)
        User.Save: err := DB.Create(&u).Error
/app/jwt-gin/controllers/auth.go:33 (0x97194e)
        Register: user, err := user.Save()
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x968059)
        (*Context).Next: c.handlers[c.index](c)
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/recovery.go:102 (0x968047)
        CustomRecoveryWithWriter.func1: c.Next()
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x967184)
        (*Context).Next: c.handlers[c.index](c)
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/logger.go:249 (0x96716b)
        LoggerWithConfig.func1: c.Next()
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x966571)
        (*Context).Next: c.handlers[c.index](c)
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:633 (0x965fe0)
        (*Engine).handleHTTPRequest: c.Next()
/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:589 (0x965b11)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:3142 (0x6cb6ed)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:2044 (0x6c6aa7)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1695 (0x472e00)
        goexit: BYTE    $0x90   // NOP

[GIN] 2024/09/16 - 16:07:30 | 500 |   85.893591ms |      172.20.0.1 | POST     "/api/register"      

```


## 解決策
ユーザー登録Registerのuser.Save()時に、DBへの接続ができないエラーらしい。
しかし、DBには以下のsetup.goからUserテーブルを作ることはできていた。
結論、原因としては、setup.goの以下で引っかかっていた。
```go
DB, err := gorm.Open(driver, dbURI)
```
⇒　正しくは以下
```go
DB, err = gorm.Open(driver, dbURI)
```
DBを:=で書いたことで代入ではなく宣言扱いになってしまい、他の関数からDBにアクセスできなくなったこと（スコープミス）が原因と思われた。
以下は、bingAIに聞いた回答。
```
`DB, err := gorm.Open(driver, dbURI)` と `DB, err = gorm.Open(driver, dbURI)` の違いは、変数のスコープにあります。

1. **`DB, err := gorm.Open(driver, dbURI)`**:
   - これは新しい変数 `DB` と `err` を関数内で宣言しています。この場合、関数内で宣言された `DB` 変数は、パッケージレベルで宣言された `DB` 変数とは異なるため、パッケージレベルの `DB` 変数は更新されません。
   - その結果、関数外で `DB` を参照すると `nil` のままになり、エラーが発生します。

2. **`DB, err = gorm.Open(driver, dbURI)`**:
   - これは既にパッケージレベルで宣言されている `DB` 変数と `err` 変数に値を代入しています。この場合、パッケージレベルの `DB` 変数が更新されるため、関数外でも正しく初期化された `DB` を参照できます。

したがって、`DB, err = gorm.Open(driver, dbURI)` を使用することで、パッケージレベルの `DB` 変数が正しく初期化され、他の関数からもアクセスできるようになります。
```


<br/>