Need advice how to use service when creating an object of different type from another type of object in GRAILS

66 Views Asked by At

This example is about having a request from a customer where the seller can choose to make an offer to the customer.

The request is stored in a class named 'Request' and the offer is stored in the class 'Offer'.

The flow is:

  1. The seller picks up a request from the request-list and is redirected to the Request.show-form.

  2. Here he can choose, by a link, to create an offer using the data in this request.

  3. Now the seller is redirected to the Offer.Create-form which is filled with data from the request.

  4. The seller now can add and or change data and the either confirm or cancel this offer.

That's it.

My idea is that the Request-controller, after receiving the action, will take the ID of the request then calling a service, Offer_service, which in turn reads the request using the ID and then creates a new Offer-object. The service continues with filling this object with data from the request-object and then calling the Offer-controller to open up the create-form to let the seller complete the offer.

I want to know if I'm on the right way or if I'm missing something?

Of course, this is simple for you, experienced people but for me... I'm new and feel like beeing on deep water sometimes. I would appreciate every type of advices, tips etc. that can lead me forward.

Amendment.. You see, we want to keep request and offer independent of each other and if the seller wants to change some of the values from the request he will do that to the offer only. The values in the request should be unchanged. And more, the id of the offer should be stored in the request so you can jump directly from a request-form to the offer if wanted. And vice-versa an id to the request should be stored in the offer to make it possible to go back to request. But those links(id:s) should only be set if the offer is saved (confirmed). It is also a possibility that more processing should be done to the request-data before it is stored in the offer. An offer may also be constructed without a request behind and then there is no connection to the request. That's why I think a service should be good to keep request and offer independent of each other.

1

There are 1 best solutions below

13
V H On

Think you are over complicating things. In short when you have the id of the request. for offer object that is all it needs.

so here goes:

<!-- this is in your gsp form that will be sending to request controller -maybe possibly it shold OfferController -->
<g:hiddenField name="userRequest.id" value="${instance.id}"/>

In that controller

def MyController {

   def actionOffer(OfferBean bean) {
        bean.formatBean()
        if (!bean.hasErrors()) {
            //do SOmething
            render view:'myView', model:[instance:bean]
            return
        } 

        render view:'failedView', model:[instance:bean]
   }
 }

in src/main/groovy/package/OfferBean.groovy

class OfferBean implements Validateable {
   // this is your actual request class
   UserRequestBean userRequestBean
   UserRequest userRequest

   static constraints = {
     request(nullable:false) //, validator:checkRequest)
   }

   def formatBean() {
    UserRequestBean userRequestBean = new UserRequestBean()
    userRequestBean.formatBean(request)
   }

  //You actually do not need this at all. 

  static def checkRequest = { val, obj, errors ->
        if (!Request.get(obj.request.id)) {
            errors.rejectValue('message','invalid.requestId',[val] as Object[],'')
        }
    }
}

Basically all you need is the userRequest.id as a hidden params passed to the validation class of OfferBean with the constraints set as false this means if the userRequest.id did not magically bind with UserRequest domain class it will invalidate and fall outside of the do Something block which has a return telling it all was okay and processed within that block

Most importantly once the binding has happened i.e. no issues you auto magically then can access all the request elements from within the bean within actionOffer gsp

Do you see what I mean by complicating when comparing above to what you wrote ?

updated controller to show how you pass bean back to view. in the acionOffer myView gsp if you now refer to ${instance.userRequestBean.something} this will map and return back the something object from within request. (no need to build anything up) once you have the id

So after reading your comments what you then need is another bean for the request, when a request object is saved in the bean like below you already have the bean. Anyhow assuming you

in src/main/groovy/package/UserRequestBean.groovy

 class UserRequestBean implements Validateable {
   def id 
   String name
   //mapped like your UserRequestBean domain class 
   //meaning it contains all elements

   //Now a function to map in actual user request
   //into this bean
   protected def formatBean(UserRequest ur) {
    this.id=ur.id
    this.name=ur.name
    //and so on

    return this
   }

}

reveiew the updated code, I have added a new formatBean function which called in main class that then binds a new userRequestBean that now contains all the elements of your actual userRequest domain class - you now can access those on the new form as userRequestBean.

I still don't think you need all this complexity.

You say user then wants to update the request so what as it was originally you get ${instance.userRequest} entire object you simply repeat the form with the existing values, upon save you then have to capture them again so you re-apply existing code that saved original object to these params,

anyhow i have shown you a far more complex way of binding a real domain class to a transient object (non database) when you are happy you can

then save those values back over the main class you could introduce


def loadValues() { 
  Map values=[:]
  //mapping all domain class objects back form bean 
  //required ones
  values.with { 
    id=this.id
    name=this.name
   }
  return values
}

then your object.properties=bean.loadValues()