monoculum/formam

Array of model problem

Closed this issue · 15 comments

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
	}
}

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?

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?

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.

Okay, I'll try and see. Thanks

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

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

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

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

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.

thanks you.

No... Thanks to you.

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
}

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.

@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.

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