Вопрос

From logic point of view I am trying to preserve partial form data between redirects for better user experience so user won't have to fill entire form again, just the part that was invalid.

From programing point of view I am trying to save request.PostForm data structure in gorilla session's flashes. The only thing I manage to retrieve after redirect is string representation of memory address like this [0xc2001c8b10].

Here is the part where I save flashes data after validation error (request.ParseForm() was executed before this):

session, _ := store.Get(request, "test")
session.AddFlash(err.Error(), "messages")
session.AddFlash(request.PostForm, "form_data")
session.Save(request, response)
http.Redirect(response, request, "/", http.StatusFound)
return

Also I tried registering structure with gob without effect:

func init() {
    gob.Register(&url.Values{})
}

Form values are in lower case, eg. "first_name", "last_name" if that could have any influence on this behavior.

Please keep in mind that I successfully manage to retrieve "messages" after redirect, only problem I have is with structural data.

Am I doing something wrong or is there maybe another approach to fill partial forms after redirect that I am not aware of?

Это было полезно?

Решение

Your problem is that you're working with values of type interface{}, which is the generic type and used when there can be more than one type. This is the case for gorilla's session.Flashes() method as it can return arbitrary user data (whatever you put in).

You can reproduce what you're experiencing with this code (on play):

type MyData struct {
    X int
}

// Simulate Flashes() from gorilla, which returns a slice of interface{} values.
func Flashes() []interface{} {
    x := &MyData{2}

    // Convert x to type interface{}
    interfaceValue := interface{}(x)

    // Put converted x into a slice of type []interface{}
    return []interface{}{interfaceValue}
}

func main() {
    // See that [0xSOMETHING] is printed
    fmt.Println("Some data:", Flashes())
}

When running this program you will see output like this:

Some data: [0xc010000000]

This is the same you're experiencing. The reason for this is that fmt.Println does not step through all levels of abstraction of pointers and interfaces and stops at a certain level unless you tell it to print everything. So if you use

fmt.Printf("Some data: %#v\n", Flashes())

you will indeed see your data:

Some data: []interface {}{(*main.MyData)(0xc010000000)}

What you have to do to access the data is to match the resulted data for the type you're expecting. You have to do a type assertion (example on play):

func main() {
    value := Flashes()[0]

    v, ok := value.(*MyData)

    if ok {
        fmt.Println("Some data:", v)
    } else {
        fmt.Println("Oh no, there's something else stored than expected")
    }
}

In the example above the first flash returned by Flashes() is used and asserted to be of type *MyData. If it is indeed this type, then it's value is printed to the console. Otherwise an error message (albeit not a good one) is printed to the console. After asserting a variable of being some type, the asserted value is of the asserted type. That is the v in the example above is of type *MyType.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top