Reputation: 58622
I have a simple problem. I need to manage a hasMany collection on a domain object. I thought I was doing it correct, but it didn't work. I found another post but it is very dated and does not work (Handling parameters from dynamic form for one-to-many relationships in grails)
class User{
static hasMany = ['prefs': Preference]
}
class Preference{
Boolean email
Boolean site
Date dateCreated
Date lastUpdated
}
GSP
<g:each var="t" in="${user.prefs}" status="idx">
<li>
<input type='hidden' name="prefs[${idx}].id" value="${t.id}"/>
Email: <g:checkBox name="prefs[${idx}].email" value="${t.email}" />
Site: <g:checkBox name="prefs[${idx}].site" value="${t.site}" /><
</li>
</g:each>
Controller:
log.info(user.prefs)
user.properties = params
if(!user.save()){ ... }
It then errors out:
UserController - [Preference : 3, Preference : 4]
Error 2013-06-04 21:54:41,405 [http-bio-8080-exec-12] ERROR errors.GrailsExceptionResolver
IndexOutOfBoundsException occurred when processing request: [POST] /user/prefs - parameters: prefs[0].email:
id: 2
prefs[1].site: on
prefs[0].email: on
_prefs[1].site:
_prefs[1].email:
prefs[1].id: 3
_prefs[0].site:
prefs[0].site: on
prefs[0].id: 4
Index: 1, Size: 1. Stacktrace follows:
Message: Index: 1, Size: 1
Upvotes: 0
Views: 275
Reputation: 58622
So I ended up fixing this and it was a hybrid approach. @Meam was correct, it was an ordering issue, but instead of worrying about ordering I just used @dmahapatro 's approach and set Preference to be a list. A side note on this is the definition of List preference
has to come before the static hasMany
definition. Or you will get a random error when trying to create User. Lastly, when you originally setup the relationship you have to use addTo
to link the two...
class User{
List preference
static hasMany = ['prefs': Preference]
}
//another thing I did not know in order to originaly link
//the two when using lists, you have to use addTo...
user.addToPrefs(
new Preference(email: true, site:false)
)
The last thing I wanted to mention is there is a bug in <g:checkbox>
if you use it with a hasMany like I did it will not work if you try to uncheck the value. I was able to work around it via coping the code from github for FormTagLib. And then updated the code with the other post i was reading https://stackoverflow.com/a/2942667/256793 that has a solution but it was a little dated. So here is the updated version:
//old code
//out << "<input type=\"hidden\" name=\"_${name}\""
//new...
def begin = name.lastIndexOf('.') +1
def tail = name.substring( begin);
out << "<input type=\"hidden\" name=\"${name.replace( tail, "_" + tail )}\" "
Upvotes: 0
Reputation: 266
I found this problem few days ago. And spent 2 days to fix it.
You have to make sure that children index in params is ordered same as parent's object. In this case, the children's order is [Preference: 3, Preference: 4]. But the params order is prefs[0].id = 4, prefs[1].id = 3. The order is different.
I have to reorder the children index in params before bind them.
Upvotes: 1