views:

95

answers:

3

Controller for a Bug:

this is the create method for a bug, I printed out bugInstance.activities and it had my activity object in it

def create = {
        def bugInstance = new Bug()
        def activity = new Activity(description:"created")

        bugInstance.properties = params
        bugInstance.addToActivities(activity)
        return [bugInstance: bugInstance]
    }

Then I looked at the save method, and printed the exact same thing, and the result is null, so somehow it's lost the activity I created, and I have no idea why. Is this really the default behavior? Am I doing something really basic wrong, because there doesn't seem to be any reason such a simple piece of code wouldn't work.

def save = {

    def bugInstance = new Bug(params)
    println bugInstance.activities
    if (bugInstance.save(flush: true)) {
        flash.message = "${message(code: 'default.created.message', args: [message(code: 'bug.label', default: 'Bug'), bugInstance.id])}"
        redirect(action: "show", id: bugInstance.id)
    }
    else {
        render(view: "create", model: [bugInstance: bugInstance])
    }
}

I know I can work around this by adding the activity in the save method, but why do I lose the activity from create() -> save()

A: 

might sound like a stupid question but are you setting a hidden parameter or anything in the create.gsp with the Bug Instance instantiated in the create?? I mean, I don't see anything wrong with what your doing here. What does your create.gsp look like?

croteau
I don't, I included all the necessary. code to the best of my knowledge. Grails doesn't pass this object through the model as I'd expected, it just gets recreated when the form submits. But there still should be a OO way to do what I'm trying here
walnutmon
+1  A: 

You never call save() on the new instance:

def create = {
   def bugInstance = new Bug()
   def activity = new Activity(description:"created")

   bugInstance.properties = params
   bugInstance.addToActivities(activity)
   bugInstance.save()
   return [bugInstance: bugInstance]
}

You don't need to save the Activity because it'll be transitively saved since it's in the activities collection.

Burt Beckwith
Yes, that would probably work as long as I sent the persisted bugInstance (with the ID generated and stored as it's property), but then bugs would be saved when the user navigates to the create page, not when they actually choose save. But this does point to the fact that I should be adding the activity in the save() controller method. Point remains though, how would you pass one to the other in a clean object oriented way?
walnutmon
A: 

If you are using the auto-generated create.gsp the activities set will not be included in the form. It is of course there in the model, but there will be no activities field rendered on the client side. When it comes back to save, it is clear that the activity is lost. Depending on what you want to achieve you could add some activity selector to the create.gsp or (to start with) a hidden field with your activities description, but then in the save action I guess you have to handle the the activities param in any case, as the magic of grails doesn't go as far as instanciating the Activity for you. The same way as you instantiate the Bug itself in the save action, you have to instantiate the Activity and even save it, if you want it to be persisted.

Edit: If you really want to pass around the whole activities list, you could make use of indexed properties.

In create.gsp add this:

<g:each status="i" var="activity" in="${bugInstance.activities}">
  <!-- one hidden field for each property of each attached activity  -->
  <g:hiddenField
    name="activities[${i}].description"
    value="${activity.description}" />
</g:each>

And in the save method this:

params.activities.each{ activity ->
  bugInstance.addToActivities(new Activity(activity))
}

But in your case it might be sufficient to instantiate the one activity from a single field.

hlg