monoculum / formam

a package for decode form's values into struct in Go
Apache License 2.0
190 stars 19 forks source link

Array of model problem #28

Closed dmuriel closed 4 years ago

dmuriel commented 4 years ago

First of all, I hope to make myself understood. Sometimes when I try to bind the form, the values are incomplete, sometimes I just receive 1 user, other times I receive 2 users, but with empty fields like:

USERS-----------------------> 2
User 1 FN-----------------------> FirstName1
User 1 LN-----------------------> LastName1
User 1 EA-----------------------> Email1@test.com
User 2 FN-----------------------> FirstName2
User 2 LN-----------------------> LastName2
User 2 EA-----------------------> 

I'm not really sure why this is happening. Thanks in advance.

I have this model:

type User struct {
    FirstName string  `form:"FirstName"`
    LastName  string  `form:"LastName"`
    Email     string  `form:"Email"`
}

type Users []User

My HTML Form (or something like that):

<form method="POST">
  <input type="text" name="User[0].FirstName" value="FirstName1">
  <input type="text" name="User[0].LastName" value="LastName1">
  <input type="text" name="User[0].Email" value="Email1@test.com">
  <input type="text" name="User[1].FirstName" value="FirstName2">
  <input type="text" name="User[1].LastName" value="LastName2">
  <input type="text" name="User[1].Email" value="Email2@test.com">
  <input type="submit">
</form>

My Handler

func MyHandler(w http.ResponseWriter, req *http.Request) error {
    decoder = formam.NewDecoder(&formam.DecoderOptions{
        TagName:           "form",
        IgnoreUnknownKeys: true,
    })

    if err := req.ParseForm(); err != nil {
        return err
    }

        u := &models.Users{}
    if err := decoder.Decode(req.Form, u); err != nil {
        return err
    }
}
emilgpa commented 4 years ago

It is strange... I can't reproduce it...

func TestArray(t *testing.T) {
    func TestArray(t *testing.T) {
    type User struct {
        FirstName string `form:"FirstName"`
        LastName  string `form:"LastName"`
        Email     string `form:"Email"`
    }
    c := struct {
        Users []User
    }{}
    vals := url.Values{
        "Users[0].FirstName": []string{"FirstName1"},
        "Users[0].LastName":  []string{"LastName1"},
        "Users[0].Email":     []string{"Email1@test.com"},
        "Users[1].FirstName": []string{"FirstName2"},
        "Users[1].LastName":  []string{"LastName2"},
        "Users[1].Email":     []string{"Email2@test.com"},
    }

    dec := NewDecoder(&DecoderOptions{})
    err := dec.Decode(vals, &c)
    if err != nil {
        t.Error(err)
    }

    t.Log("c ->", c)
}

I have a question: I see that you use "User[0]", so User points to a struct with a field named 'User' and it is an array of User type?

dmuriel commented 4 years ago

No... I'm using the model "users" which is an array of the struct named User, so I expect something like:

Users {
   {
      "FirstName": "FirstName1"
      "LastName":  "LastName1"
      "Email":     "Email1@test.com"
   },
   {
      "FirstName": "FirstName2"
      "LastName":  "LastName2"
      "Email":     "Email2@test.com"
   },
}

Maybe i'm using wrong the form?

emilgpa commented 4 years ago

Yes, you are using it wrong. "User[0]" means for forman "searchs by a field named 'User' in the struct that I pass you".

If you want pass a array to decode then in the html form change "User[index_here]" to "[index_here]". I means, remove "User" in the beginning.

dmuriel commented 4 years ago

Okay, I'll try and see. Thanks

dmuriel commented 4 years ago

@emilgpa sorry, I tried as you said but is still working sometimes.

emilgpa commented 4 years ago

include code (go and html) to reproduce it because by test I cannot reproduce it

emilgpa commented 4 years ago

A question: Are you sure that the request from browser always send all data?

dmuriel commented 4 years ago

Yes... I know is strange, the browser sends the data and the server receives the form's values but when I try to parse it, some data goes missing. Also, I'm using Buffalo, and they have a method called "Bind" which uses formam so I'm not sure how to share the code with you. I'm uploading 3 screens for you to see. I hope these can help.

Screen Shot 2019-11-27 at 2 36 23 PM

Screen Shot 2019-11-27 at 2 37 10 PM Screen Shot 2019-11-27 at 2 38 17 PM

if you can't see well the third image, this is a transcribed version:

INFO[2019-11-27T14:35:40Z] /daniels-company/users/ admin_id=11cfe6b5-514e-4a4b-92b6-92cf48bde69e content_type=application/x-www-form-urlencoded db=23.167117ms duration=393.943262ms form="{\"[0].Email\":[\"Email1@test.com\"],\"[0].FirstName\":[\"FirstName1\"],\"[0].LastName\":[\"LastName1\"],\"[1].Email\":[\"Email2@test.com\"],\"[1].FirstName\":[\"FirstName2\"],\"[1].LastName\":[\"LastName2\"],\"authenticity_token\":[\"lH9Iio/8prdUZOq5SCgn9qIUy7zEYcZFSCNNoOcwcLwPMKsmUlY5rTHMxRGTJy+3lUY7msQ6n7YCg7Y+A4NzRw==\"]}" human_size="0 B" method=POST params="{\"[0].Email\":[\"Email1@test.com\"],\"[0].FirstName\":[\"FirstName1\"],\"[0].LastName\":[\"LastName1\"],\"[1].Email\":[\"Email2@test.com\"],\"[1].FirstName\":[\"FirstName2\"],\"[1].LastName\":[\"LastName2\"],\"authenticity_token\":[\"lH9Iio/8prdUZOq5SCgn9qIUy7zEYcZFSCNNoOcwcLwPMKsmUlY5rTHMxRGTJy+3lUY7msQ6n7YCg7Y+A4NzRw==\"],\"slug_name\":[\"daniels-company\"]}" path=/daniels-company/users/ request_id=2be758ccfc54e52d4f28-4dfd0f5e92f820cd560f size=0 status=302
emilgpa commented 4 years ago

ok, I found the error. The form data includes "authenticity_token". Right now, the test fails. When I get home, I hope to fix it.

emilgpa commented 4 years ago

thanks you.

dmuriel commented 4 years ago

No... Thanks to you.

emilgpa commented 4 years ago

Sorry for my delay. For the moment, you can include "authenticity_token" to your struct and you should be ok. This weekend I hope fix it.

type FormUsers struct {
    Token string `form:"authenticity_token"`
    Users Users
}
arp242 commented 4 years ago

I added a branch with a failing test case; see the message above.

I took a brief look at fixing it, but no obvious solution.

emilgpa commented 4 years ago

@arp242 thanks you! I haven't had time to fix it. I expect look it again this weekend and to see that we are can to do. thanks again.

emilgpa commented 4 years ago

sorry for the delay. This has been fixed with the latest commit.