Reputation: 411
I have a somewhat basic Q/A application and I'm having problem changing the order of my answers. The answers are displayed through the Ordinal
property which has a unique constraint
.
class Answer {
DateTime dateCreated
DateTime lastUpdated
String body
Integer ordinal
String reason
static belongsTo = [question: Question]
static constraints = {
body blank: false
ordinal unique: 'question'
}
String toString() {
"Answer: $body"
}
}
class Question {
DateTime dateCreated
DateTime lastUpdated
String body
Answer correctAnswer
Integer ordinal
static belongsTo = [lesson: Lesson]
static hasMany = [answers: Answer]
static constraints = {
body blank: false
correctAnswer nullable: true,
validator: { Answer val, Question obj ->
val ? val.question == obj : true // TODO: Give this a proper error message
}
ordinal unique: 'lesson'
}
static mapping = {
lesson lazy: true
answers sort: 'ordinal'
}
}
I update the ordinals through a form
<g:each status="i" in="${questionInstance.answers}" var="answer">
<input type="number" name="answers[${i}].ordinal" value="${answer?.ordinal}" />: ${answer}
</g:each>
the params binds to the questionInstance.answers
object and updates the ordinal
fields the each answer
def update(Long id, Long version) {
def questionInstance = Question.get(id)
questionInstance.properties = params
if (!questionInstance.save(flush: true)) {
render(view: "edit", model: [questionInstance: questionInstance])
return
}
redirect(action: "index", id: questionInstance.id)
}
this is what my questionInstance.answers
object looks like before I bind the params
after the params
are assigned. Notice that answers
has changed from hibernate.collection.PersistentSet
to grails.web.binding.ListOrderedSet
No signature of method: edu.example.work_department.website.Question$__clinit__closure1_closure3.doCall() is applicable for argument types: (edu.example.work_department.website.Answer, edu.example.work_department.website.Question) values: [Answer: Answer 2, edu.example.work_department.website.Question : 1]
Possible solutions: doCall(edu.example.work_department.website.Answer, edu.example.work_department.website.Question), call(), call([Ljava.lang.Object;), call(java.lang.Object), call(edu.example.work_department.website.Answer, edu.example.work_department.website.Question), findAll()
The following classes appear as argument class and as parameter class, but are defined by different class loader:
edu.example.work_department.website.Answer (defined by 'java.net.URLClassLoader@689319a1' and 'groovy.lang.GroovyClassLoader@8db6e40'), edu.example.work_department.website.Question (defined by 'java.net.URLClassLoader@689319a1' and 'groovy.lang.GroovyClassLoader@8db6e40')
If one of the method suggestions matches the method you wanted to call,
then check your class loader setup.. Stacktrace follows:
'groovy.lang.MissingMethodException: No signature of method: edu.example.work_department.website.Question$__clinit__closure1_closure3.doCall() is applicable for argument types: (edu.example.work_department.website.Answer, edu.example.work_department.website.Question) values: [Answer: Answer 2, edu.example.work_department.website.Question : 1]
Possible solutions: doCall(edu.example.work_department.website.Answer, edu.example.work_department.website.Question), call(), call([Ljava.lang.Object;), call(java.lang.Object), call(edu.example.work_department.website.Answer, edu.example.work_department.website.Question), findAll()
The following classes appear as argument class and as parameter class, but are defined by different class loader:
edu.example.work_department.website.Answer (defined by 'java.net.URLClassLoader@689319a1' and 'groovy.lang.GroovyClassLoader@8db6e40'), edu.example.work_department.website.Question (defined by 'java.net.URLClassLoader@689319a1' and 'groovy.lang.GroovyClassLoader@8db6e40')
If one of the method suggestions matches the method you wanted to call,
The error occurs when hitting the questionInstance.save()
command. What am I doing wrong that it doesn't like my argument types?
Upvotes: 0
Views: 226
Reputation: 1182
It is better to avoid data binding with
object.properties = params
Apart from this, you can use Command classes grails command class creation
And you can bind data using command class object.
For your Domain class Answer
create command class as :
Class AnswerCommand {
String body
Integer ordinal
String reason
static constraints = {
body blank: false
ordinal unique: 'question'
}
}
and read the params as command class object.
def update(Long id, Long version, AnswerCommand answerCmd) {
def questionInstance = Question.get(id)
//questionInstance.properties = params // use the below codes.
questionInstance.body = answerCmd.body
questionInstance.ordinal = answerCmd.ordinal
questionInstance.reason = answerCmd.reason
//here you can use bindData() also. But this is for making you a clear picture.
if (!questionInstance.save(flush: true)) {
render(view: "edit", model: [questionInstance: questionInstance])
return
}
redirect(action: "index", id: questionInstance.id)
}
Upvotes: 3