Grails Session scope for service not working as expected - grails

I'm making a web app that stores reports of various types as domain objects, so I have a domain object HeadOfHousehold which contains name data, and references to other domain objects such as the reports, addresses, and any dependants. I am trying to build a list of recently viewed/created HeadOfHousehold objects. After multiple Google searches, and scouring the manual, it appeared that a service would be an appropriate solution. So I created ClientListService:
#Transactional
class ClientListService {
static scope = "session"
String message // right now I'll be happy to just see the same message across
// pages I can add a list and manipulate it later.
}
I thought I could then reference it in my various controllers, and it would persist Something like this:
def clientListService
def index(){
hasSearched = false
clientListService = new ClientListService(message: "Hello")
[errorMessage: params.errorMessage, clients:clientListService]
}
Which should be available in a later controller:
class HeadOfHouseHoldController {
def clientListService
def index() {
[customer: HeadOfHousehold.get(params.id), clients: clientListService]
}//...
However when I try to get the message, it appears as if the object is null.
From my index.gsp:
***************${clients?.message}********************
So I don't know if I am not defining session properly (I'm not doing anything special to do so), if I'm misunderstanding how the session scope works, or something else. I do see the proper message on the original page which has defined the object, however I don't see it on any subsequent pages.
Also, I'm not sure if this is the proper way to go about this; right now all I really need is the list of HeadOfHouseholds that I would need (so I can add to the list from other pages), however I can see possibly adding other logic and items into such a class.

I think you understood the session scope correctly. Each Spring bean with a session scope is bound to the HTTP session.
But your first controller listing does it all wrong. You are not supposed to instantiate the service class yourself. This is what Spring (Grails) does.
class FooController {
def clientListService // gets autowired by Grails/Spring
def index(){
hasSearched = false
clientListService.message = 'Hello' // only assign a String value to the service
[errorMessage: params.errorMessage, clients:clientListService]
}
}
This means you cannot not do something like
clientListService = new ClientListService(message: "Hello")
and expect your code to work. Hope this helps.

Related

Grails - Pass data from view to controller

I'm trying to pass Param data from view to controller and I'm having trouble. Here's what I'm currently trying to do.
View:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
Controller:
def myObjectService //inject service object
def doStuff = {
myObjectService.doStuff("${params.keyId}") //this blows up because it's value of NULL
myObjectService.doStuff(8) //this works fine
}
It gets to the method block because the error log says "no signature of method MyObject.doStuff() is applicable for argument types: values: [null]." Also, I'm able to see ${mykey.id[i]} data from another field, so the data is definitely in the view.
How can I get the controller to read the Param data?
Thanks!
err lots wrong here:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
why not use:
<g:form name="something" controller="yourController" action="youraction">
As you can see above you are having to generate
form url (maybe you have your reasons)
Controller:
def doStuff = {
MyObject.doStuff("${params.keyId}")
}
Differences between action and methods in Grails controllers
So firstly why you should change controller but my actual concern here is
MyObject.doStuff
is MyObject.doStuff a static method ?
since that is only when a call like this would work. The link shows a static method. gets called here and it may confuse you due to it calling it via executor.registerSenderFault due to how it is generated working - expandability - for future classes that do same thing. this could have been EmailExecutor.registerSenderFault which is the full class in uppercase like you have declared.
surely it should be a service notice starting with lower case.
myObjectServive.doStuff(stuff)
If above is some real method in MyObject and is not a static method then you need to instantiate the class
MyObject myObject = new MyObject()
myObject.doStuff(stuff)
but in short this is why services exist it is all there to save you all the hassle since they just get injected.
I suggest you do some reading looking around
E2A
def doStuff = {
println "my params are $params "
//do you see keyId in there ?
//if so what is doStuff expecting as input a string ?:
// since if you do
println "${params.keyId.getClass()}"
//by default it will be a string you may need to change it from:
//myObjectService.doStuff("${params.keyId}")
myObjectService.doStuff(params.keyId as Long)
}
Personally I don't think it is any of the above edited comments, it still relates to how/what you are injecting. I have seen similar issues. I would suggest you create a brand new service and inject new service as a test and start again - not convinced you were injecting it correctly or if you are the service may be some abstract class rather than a normal service. Or.... you are making some form of similar mistake in the uppercase/lowercase declaration of the service name so you may have created:
MyObjectnameService and calling it using myObjectNameService difference in N in those or.... even worse you have created actual service as myObjectNameService with lowercase name.
test this all again using a much simpler naming convention and create a new service as a test
grails create service MyService
and try again using this service

Grails - the use of service layer

I have problems in organizing my code when I want to update a non-simple domain object. The problem is to separate responsibilities for the controller and the service layer.
More explicitly, assume that we have a domain class Client that depends on other domain classes like Address and so on.
In the view there is a gsp for editing some of the Clients properties including some of the nested properties like street on the Address.
When I would like to update those fields I call the update method on a Controller (in this case the ClientController).
I like the feature coming from the errors of a domain class when validated. Like if I in the Controller write
Client client = Client.get(params.id)
client.properties = params
client.validate()
If the client now has errors it is very easy to display them in the edit view.
But, I thought that updating, saving and getting the client from the database (Client.get(theId)) should be handled by the service layer. In my case I have to update or create other domain objects (like the Address) before I update the Client.
So one of my questions are how should the API look like for the service layer?
public ... updateClient(…)
In the literature they have the trivial example of updating the age of a person. So, their API consists of the id of the person and the new age. But, in my case I have about ten params from the view and they are just a subset of all properties of a client and I don't know which one of these that have changed.
I would like to have a Client in the controller that I can validate and resend to the edit view if it has validation errors.
I would like to handle the database interactions and transactions from the service layer.
How can I combine these? What responsibilities should the different layers have regarding update? How should the API of the service layer look like regarding update?
If there is a good reference implementation somewhere I would be happy to study it. Many times the service layer is unfortunately totally or partially ignored.
The missing piece of this puzzle is command objects. These classes represent the contract for your API into your services and provide you the ability to have a concrete class for your views and for validation. Let's look at an example.
Given a domain class of Client which as an Address and several Phone instances your Service layer might look like this:
...
class ClientService {
def updateClient(ClientUpdateCommand cmd) {
..
}
}
...
While the ClientUpdateCommand looks something like this:
#grails.validation.Validateable
class ClientUpdateCommand {
Long id
String name
List<PhoneUpdateCommand> phoneNumbers = []
AddressUpdateCommand address = new AddressUpdateCommand()
...
static constraints {
id(nullable: false)
name(nullable: false, blank: false, size:1..50)
...
}
...
}
You will note that this command object is composed of other command objects, and has constraints for validation. It may seem like you are replicating your domain classes here, but I have found that the more complex your application then more differences will appear between the domain classes and your command objects.
Next up is the use of the command object within your controller and your views. A controller method may look something like this:
Class ClientController {
...
def clientService
...
def edit(ClientUpdateCommand cmd) {
...
cmd = clientService.load(cmd.id)
Map model = [client: cmd]
render(view: 'edit', model: model)
}
def update(ClientUpdateCommand cmd) {
Map model = [client: cmd]
if (cmd.hasErrors() {
render(view: 'edit', model: model]
return
} else {
clientService.update(cmd)
...
}
...
}
}
I have left a lot out of the controller as I didn't want to bore you with the details but rather show how a command object replaces the domain instance. In some ways it's a little bit more work but it moves you completely away from manipulating the domain classes and delegates that to the service you have created. You will also notice that the command object replaces the domain class instance for your model for your views. I won't bother giving you any examples of the GSPs since they really don't change much when using command objects like this.
I'm sure there could be entire chapters of books written on the subject, but hopefully this gives you some insight and you can see that the answer to your question(s) is: Command objects.

Grails: how to retrieve a persistent value for the collection?

I'm writing a Grails application and I need to retrieve a persistent value for the collection of my domain class objects. Let's consider we have got the following domain object:
class UserGroup {
SortedSet<User> users
static hasMany = [ users: User ]
// ...
def beforeUpdate() {
println "BEFORE UPDATE: " + this.getPersistentValue('users');
}
}
class User implements Comparable<User> {
String name
}
And the controller which has the following action:
class UserGroupController {
def addUser() {
UserGroup group = UserGroup.get(params.long('gid'))
User user = User.get(params.long('uid'))
group.addToUsers(user)
group.save(failOnError:true, flush:true)
}
}
The problem is that when beforeUpdate() is called, the users collection already contains the recently added user. So, seems that addTo() method doesn't trigger the beforeUpdate() event.
The same problem occurs when we're talking about isDirty() method. As the changes are applied before the beforeUpdate() is called, the collection is not recognized as dirty field.
Does anyone know how to change this? I'm writing a feature which tracks the history of changes for lots of different object, so I need to have access to the previous value in order to understand whether its value was changed or not.
I have had a similar issue, where things are being updated when I wasn't expecting them when I used the .get() on domain classes. I like to use .read() now because it wont update the database when I'm not expecting it to. Grails does a lot of sneaky things behind the sense which are helpful I think but can be a bit confusing.

Referring to Related Record ID In Controller On Save()

I'm still new to Grails and GORM and I got stumped on this and wasn't able to figure out what I am doing wrong. The intent is to automatically relate the record to the logged in user through the Shiro plugin for Grails.
Class User { static hasMany = [stuff: Stuff] }
Class Stuff { static belongsTo = [user:User] }
Class StuffController {
def create = {
params.put('user', User.createCriteria().get{eq('username',SecurityUtils.subject.principal)}.id)
def stuffInstance = new Stuff(params)
stuffInstance.save()
}
}
I saw in the generate-views version of the create scaffold that the relevant field was referred to as name="user.id", but neither it nor variants (such as user_id) seems to work. The query to the Users domain returns the record id necessary, and params.put in this context seems to correctly append the params object with the new value when I render to a test page (so I'm guessing it's not immutable), but this is what I get from the save():
Property [user] of class [class org.stuffing.Stuff] cannot be null
I've even tried flipping it around and going the other way, with the same result:
User.createCriteria().get{eq('username',SecurityUtils.subject.principal)}
.addToStuff(new Stuff(params))`
.save()
Anyone able to enlighten me on what I'm missing here?
Thanks!
EDIT:
Apparently I was being braindead; I was overriding the "create" method, but the default action is "save" in the _form.gsp template, so it wasn't executing that branch.
On the plus side, I did learn about dynamic finders via Burt below, so it wasn't a total wash.
Thanks for your time, guys!
Your code can be a lot cleaner - there's no reason to use createCriteria here. If you're searching by username, use a dynamic finder:
def stuffInstance = new Stuff(params)
def user = User.findByUsername(SecurityUtils.subject.principal)
stuffInstance.user = user
if (!stuffInstance.save()) {
// inspect stuffInstance.errors
}

Do I have to use webflows?

I want to collect the data for a domain class over a few forms. I'd like to initialise an instance of the domain, carry it through the form pages (assigning the collected data to the properties of the instance) and save the instance after the last form is completed successfully.
Is there a way to do this without webflows?
Is there a way to do this without webflows?
You can use hidden fields to accomplish this. But I may prefer you to use Webflows.
Here are some advantages of using Webflows:
1)You got two new scopes flow and conversation allows you to store variables, which are accessed within your flow
2)You have simple DSL to keep things tidy
3)Since there is a flow scope, you can do something like this:
flow.someThing = new YourClassName(params) //places object in flow scope
Keep in Mind:
1)If you use flow-scoped objects your class need to be implemented Serializable class.
2)And from Grails 1.2, you need to install Webflow plugin explicitly. Document says this:
From Grails 1.2 onwards Webflow is no longer in Grails core, so you
must install the Webflow plugin to use this feature: grails
install-plugin webflow
(see here).
As an alternative to Ant's comment, you could use the session, but storing a non-domain object or a simple Map. This will definitely lead to a lot of extra complexity, and the webflows do provide a lot of protection against accidental back-buttons, etc.
Rough idea:
in grails-app/domain
class Widget {
String name
int id
// constraints, etc
}
in grails-app/controllers
class WidgetCommand {
// setup your command
}
class WidgetController {
def savePage1 = { WidgetCommand cmd ->
// validate, etc
def widget = session.tempWidget ?: [:]
widget.putAll(cmd.properties)
session.tempWidget = widget
[widget: widget]
}
def savePage2 = { WidgetCommand cmd ->
// etc
}
def savePage3 = {
// or something similar here
def finalWidget = new Widget(session.tempWidget)
finalWidget.save()
}
}
You could try storing an actual domain object directly in memory, but I believe that will automatically be saved at session close if you are editing the object (as opposed to new ones), and you'll have to re-link it to the Hibernate session.

Resources