Scope Basics
You'll notice from previous examples that we used a special object called
flow to store objects within "flow scope". Grails flows have 5 different scopes you can utilize:
request - Stores an object for the scope of the current request
flash - Stores the object for the current and next request only
flow - Stores objects for the scope of the flow, removing them when the flow reaches an end state
conversation - Stores objects for the scope of the conversation including the root flow and nested subflows
session - Stores objects inside the users session
Grails service classes can be automatically scoped to a web flow scope. See the documentation on Services for more information.
Also returning a model map from an action will automatically result in the model being placed in flow scope. For example, using a transition action, you can place objects within
flow scope as follows:
enterPersonalDetails {
on("submit") {
[person:new Person(params)]
}.to "enterShipping"
on("return").to "showCart"
}Be aware that a new request is always created for each state, so an object placed in request scope in an action state (for example) will not be available in a subsequent view state. Use one of the other scopes to pass objects from one state to another. Also note that Web Flow:
- Moves objects from flash scope to request scope upon transition between states;
- Merges objects from the flow and conversation scopes into the view model before rendering (so you shouldn't include a scope prefix when referencing these objects within a view, e.g. GSP pages).
Flow Scopes and Serialization
When placing objects in
flash,
flow or
conversation scope they must implement
java.io.Serializable otherwise you will get an error. This has an impact on
domain classes in that domain classes are typically placed within a scope so that they can be rendered in a view. For example consider the following domain class:
class Book {
String title
}In order to place an instance of the
Book class in a flow scope you will need to modify it as follows:
class Book implements Serializable {
String title
}This also impacts associations and closures you declare within a domain class. For example consider this:
class Book implements Serializable {
String title
Author author
}Here if the
Author association is not
Serializable you will also get an error. This also impacts closures used in
GORM events such as
onLoad,
onSave and so on. The following domain class will cause an error if an instance is placed in a flow scope:
class Book implements Serializable {
String title
def onLoad = {
println "I'm loading"
}
}The reason is that the assigned block on the
onLoad event cannot be serialized. To get around this you should declare all events as
transient:
class Book implements Serializable {
String title
transient onLoad = {
println "I'm loading"
}
}