Building a Web Application with Martini and Gorm - Part 2

Gogophercolor

In this lesson, we will implement binding to our application, along with handling POST requests and building upon our usage of Gorm.


Our first app is cool, it works, but we aren’t taking any user input so what’s the point of that? We can’t rely on you wanting to use a MySQL client all the time. We are going to start with a new route, a new template and update our structs.

server.go

Lets update the code in our server.go file. Below the m.Get('/'... function, lets create a new router.

m.Get("/item/add", func(r render.Render) {
  var retData struct {
      Item Item
  }

    r.HTML(200, "item_edit", retData)
})
    

This is very similar to our homepage controler, the only difference is we are not calling the database, but you’ll notice in our retData variable we are setting an empty Item variable, this is because our template will be used for editing and adding items. Let’s create that template now.

templates/item_edit.tmpl

Here is the code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Edit Item</title>
</head>
<body>
    <form action="/item/save" method="post">
        <label for="title">Title</label><br>
        <input type="text" name="title" id="title" value="{{ .Item.Title }}"><br>
        <br>
        <label for="description">Description</label><br />
        <textarea name="description" id="description">{{ .Item.Description }}</textarea><br />
        <br />
        <label for="user_name">User Name</label><br>
        <input type="text" name="user_name" id="user_name" value="{{ .Item.UserName }}"><br>
        <br>
        <input type="hidden" name="id" value="{{ .Item.Id }}">
        <input type="submit" value="Save">

    </form>
</body>
</html>

This is very basic, it’s essentially a form and where the values of the data are, you can see we are using the power of Go templates to inject the data. When we are on the /item/add route, we won’t see anything there and the “id” will be set to 0, but when we edit, everything will fill in with the correct information.

You can notice we set action=“/item/save”, so lets go create that route now.

server.go

Back in the main go file, under the new /item/add route we created, lets create another:

m.Post("/item/save", binding.Bind(Item{}), func(r render.Render, i Item) {
    db.Save(&i)
    r.Redirect("/")
})

Again, this is a very small router. you can notice that before we run the function for the router, we are calling binding.Bind(Item{}). This is how our application knows to take the POST data, and associate it to an Item object that we can load in the function being called, which is the i Item we are referencing. Gorm makes it easy, by calling db.Save(&i) it knows to create a new record if i.Id is set to 0 or to update a record if it is set, this is because the default primary key in Gorm is the Id.

There are just a few more small steps we need to take before we are done. We need to update our imports to load the binding library. At the top of the server.go file, your imports should be as follows:

import (
    "github.com/go-martini/martini"
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    "github.com/martini-contrib/binding"
    "github.com/martini-contrib/render"
)

The final step to tie this all together is to update the structs.go file to tell our struct how to map to the form. Make sure your file looks like the following:

package main

type Item struct {
    Id          int64  `form:"id"`
    Title       string `form:"title"`
    Description string `form:"description"`
    UserName    string `form:"user_name"`
}

You can see we added attributes where we are assigning values to the form key, the Martini binding middleware will reference this when it grabs the info in the request to the server.

So now we can add, and on the homepage it will view the new records if you ran your application to test, but we still need to be able to edit and delete to complete our basic CRUD application. Let’s update the homepage template file with some new links and then we’ll go back to server.go to place in the final pieces.

templates/index.tmpl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>martini gorm example</title>
</head>
<body>
    <a href="/item/add">Add Item</a>
    <hr>
    <h1>Items</h1>
    {{ range .Items }}
    <h3>{{ .Title }}</h3>
    <p>{{ .Description }}</p>
    <p>By: {{ .UserName }}</p>
    <p><a href="/item/edit/{{ .Id }}">Edit</a> | <a href="/item/remove/{{ .Id }}">Remove</a></p>
    {{ else }}
    <p>No items found!</p>
    {{ end }}
</body>
</html>

Our new code should look like above, you will notice I added an Add Item link to take us to our new page, and I also created two new links below where we print the username, an Edit and Remove link. Let’s go back to our server.go page to create those new routes.

server.go

Under our /item/save route, lets add the following:

m.Get("/item/edit/:id", func(r render.Render, p martini.Params) {
  var retData struct {
      Item Item
  }

  db.Where("id = ?", p["id"]).Find(&retData.Item)

  r.HTML(200, "item_edit", retData)
})

m.Get("/item/remove/:id", func(r render.Render, p martini.Params) {
  var item Item
  db.Where("id = ?", p["id"]).Delete(&item)
  r.Redirect("/")
})

On the first new route, you can see we are telling it to look for an :id value. We are using martini.params to access that in our controller. You can notice that our Gorm query is a bit longer, where we are adding a .Where function to find the item by Id and assigning it to the retData.Item variable.

The second new route is similar to the first in it’s structure, but we are just creating an item variable which will let Gorm know easily which table to reference, and taking that same .Where statement and applying it before we run .Delete.

Wrapping it up

Now go ahead and test our your new application! You should be able to create/read/update/delete the records in the database, and you did it with a minimal amount of code, too!

Be sure to run go get in your project directory before running so all the dependencies for this application are downloaded.

We will follow this up with instructions on how we can take this live on Heroku for free, with a free 5 MB MySQL instance which is perfect for testing.

If you want to take a look at this code, it is hosted here on Github: https://github.com/dougbarrett/martini-gorm

Last Updated: 2015-01-21 06:54:11 +0000 UTC



What are your thoughts on this?

Categories

RSS feed

Follow Doug On Social