Gin   データの更新

ホーム   Goチュートリアル

データの更新


CRUD

アプリケーションが備えているべき 4 つの機能を CRUD(クラッド)と言います。データの生成(Create)、データの読み取り(Read)、データの更新・変更(Update)、データの削除(Delete)の頭文字を並べたものです

この章では、Todo アプリに、まだ搭載されていない、更新を追加したいと思います。


環境設定

次のコードで Gin、GORM、SQLite をインストールします。macOS、Mint(Ubunt)、CentOS 7で同じコードです。少し時間がかかる場合があります。


go get github.com/gin-gonic/gin
go get github.com/jinzhu/gorm
go get github.com/mattn/go-sqlite3
    

Todo


ディレクトリ構成

次のようなディレクトリ構成にします。


gin/
- main.go
- templates/
- - index.html
- - edit.html
- styles/
- - style.css
	
ディレクトリ構成、ディレクトリ名、ファイル名は自由に決めて大丈夫です。


main.go


package main

import (
	"strconv"	// for strconv.Atoi
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	/*
	sqlite3 は読み込まなければなりません
	しかし実際のデータベースの操作は、gorm で行います
	そのため、sqlite3は使わないことを、 _ で明示しなければなりません
	*/
	_ "github.com/mattn/go-sqlite3"
)

// モデルの宣言(データ構造の宣言)
type Todo struct {
	gorm.Model
	Memo string
}

func main() {
	r := gin.Default()
	r.Static("styles", "./styles")
	r.LoadHTMLGlob("templates/*.html")
	
	dbInit()
	
	// List
	r.GET("/", func(c *gin.Context) {
		todos := dbGetAll()
		c.HTML(200, "index.html", gin.H{"todos": todos})
	})
	
	// Create
	r.POST("/new", func(c *gin.Context) {
		memo := c.PostForm("memo")
		dbCreate(memo)
		c.Redirect(302, "/")
	})
	
	//Delete
	r.GET("delete/:id", func(c *gin.Context) {
		n := c.Param("id")
		id, err := strconv.Atoi(n)
		if err != nil {
			panic(err)
		}
		dbDelete(id)
		c.Redirect(302, "/")
	})
	
	// Edit
	r.GET("/edit/:id", func(c *gin.Context) {
		n := c.Param("id")
		id, err := strconv.Atoi(n)
		if err != nil {
			panic(err)
		}
		todo := dbGetOne(id)
		c.HTML(200, "edit.html", gin.H{"todo": todo})
	})
	
	// Update
	r.POST("/update/:id", func(c *gin.Context) {
		n := c.Param("id")
		id, err := strconv.Atoi(n)
		if err != nil {
			panic(err)
		}
		memo := c.PostForm("memo")
		dbUpdate(id, memo)
		c.Redirect(302, "/")
	})
		
	// Run Server
	r.Run()    // 引数を指定しないと、":8080" が指定されたことになります
}

// データベースのマイグレート(データベースの初期化)
func dbInit() {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("failed to connect database\n")
	}
	defer db.Close()
	db.AutoMigrate(&Todo{})
}

// データの作成
func dbCreate(memo string) {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("failed to connect database\n")
	}
	defer db.Close()
	db.Create(&Todo{Memo: memo})
}

// データの削除
func dbDelete(id int) {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("failed to connect database\n")
	}
	defer db.Close()
	var todo Todo
	db.First(&todo, id)
	db.Delete(&todo)
}

// データの更新
func dbUpdate(id int, memo string) {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("failed to connect database\n")
	}
	defer db.Close()
	var todo Todo
	db.First(&todo, id)
	todo.Memo = memo
	db.Save(&todo)
}

// データのすべてを取得
func dbGetAll() []Todo {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("failed to connect database\n")
	}
	defer db.Close()
	var todos []Todo
	db.Find(&todos)
	return todos
}

// データの一つを取得
func dbGetOne(id int) Todo {
	db, err := gorm.Open("sqlite3", "todo.sqlite3")
	if err != nil {
		panic("railed to connect database\n")
	}
	defer db.Close()
	var todo Todo
	db.First(&todo, id)
	return todo
}
	

初期化のところで、マイグレート(migrate)という用語が出てきました。普通の初期化は、データをすべて書き替えますが、マイグレートは、データベースに保存されているデータを保持したまま、データの追加・削除・変更を行います。データファイルがなければ新しいデータファイルを作成します。


index.html


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Todo</title>
	<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
	<h1>Todo</h1>
	<div align="center">
	<form method="post" action="/new">
		<p><font size="-1">メモ</font>
		<input type="text" name="memo" size="30" placeholder="入力してください">
		<input type="submit" value="登録"></p>
	</form>
	</div>
	<div class="container">
	<ul>
		{{ range .todos }}
			<li>{{.Memo}}
			<!-- 編集 -->
			<label>
			<a href="/edit/{{.ID}}">[編集]</a>
			</label>
			<!-- 削除 -->
			<label>
			<a onclick="var ok=confirm('本当に削除しますか?');
			if (ok) location.href='delete/{{.ID}}'; return false;"><span class="delete">[削除]</span></a>
			</label>
			</li>
		{{ end }}
	</ul>
	</div>
</body>
</html>
	


edit.html


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Edit</title>
	<link rel="stylesheet" href="../styles/style.css">
</head>
<body>
	<h1>Edit</h1>
	<div align="center">
	<form action="/update/{{.todo.ID}}" method="post">
		<p><font size="-1">メモ</font>
		<input type="text" name="memo" size="30" value="{{.todo.Memo}}">
		<input type="submit" value="送信"></p>
		</form>
	</div>
</body>
</html>
    


style.css

body {
	color: #666;
	background: darkgrey;
}

h1 {
    text-align: center;
    font-family: sans-serif;
    font-weight: 100;
    border-bottom: 1px solid lightgray;
}
.container {
    width: 330px;
    margin: auto;
    font-size: 14px;
}
a {
    color: #666;
    font-size: 12px;
    text-decoration: none;
}
ul {
    font-size: 14px;
}

.delete {
    font-size: 12px;
    cursor: pointer;
}
    


実行方法

実行する場合は、ターミナルで gin ディレクトリに移動して、go run main.go と入力して、エンターキーを押します。


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] GET    /styles/*filepath         --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers)
[GIN-debug] HEAD   /styles/*filepath         --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (3 handlers)
[GIN-debug] Loaded HTML Templates (3): 
	- 
	- edit.html
	- index.html

[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] POST   /new                      --> main.main.func2 (3 handlers)
[GIN-debug] GET    /delete/:id               --> main.main.func3 (3 handlers)
[GIN-debug] GET    /edit/:id                 --> main.main.func4 (3 handlers)
[GIN-debug] POST   /update/:id               --> main.main.func5 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
    

Gin の場合は、多くのコードが表示されます。


macOS の場合は、次のようなアラートが表示される場合があります。「許可」をクリックしてください。


実行結果

ブラウザで localhost:8080/ にアクセスすると次のように表示されます。


[編集] をクリックすると編集ページに移動します。


14264 visits
Posted: Jul. 11, 2019
Update: Jul. 11, 2019

ホーム   Goチュートリアル   目次