I'm building some crude CMS-like functionality (to get acquinted with Play Framework). For this test-case I've build 2 pages, 1 for listing tags and 1 for creating/editing/saving tags.
The flow is like this (routes-file):
#list tags
GET /tags Application.listTags
#view/edit existing tag
GET /tag/{<(?!new$)(.+)>name} Application.showTag
#new tag
GET /tag/new Application.showTag
the create/view/edit page displays a form which gets it's values from a tagDTO. The normal flow works without problems, but when the form gives validation-errors (e.g: the tag-name must exist) I want to display the page again, repopulating the form with the edited values.
For this (following the Play Framework conventions) I could use the 'flash'-object which contains these last values, but the form is already bound to the tagDTO (which is null on redirect) instead of the 'flash'-object.
First the code: Application.java
.....
public static void showTag(String name) {
TagDTO tagDTO = TagDTO.buildDTOFromModelOrNew(name);
render(tagDTO);
}
/**
* Save tag and redirect to Show
*
* @param name
* @param displayname
* @param isnew
*/
public static void saveTag(
@Required(message="Name is required") String name,
String displayname,
boolean isnew)
{
checkAuthenticity();
if(validation.hasErrors()) {
params.flash();
validation.keep();
showTag(null);
}
//fetch tagDTO based on backend or create new if not exist
TagDTO tag = TagDTO.buildDTOFromModelOrNew(name);
// Append / Overwrite values
tag.displayname = displayname;
tag.name = name;
//save result to model
TagDTO.buildAndSaveModelFromDTO(tag);
flash.success("Thanks for " + (isnew?"creating":"updating") + " tag " + tag.name);
//redirect to show
showTag(tag.name);
}
And ShowTag.html
#{extends 'main.html' /}
#{if flash.success}
<p class="success">${flash.success}</p>
#{/if}
#{ifErrors}
<p class="errors">Oops...</p>
#{/ifErrors}
#{form @Application.saveTag()}
#{authenticityToken /}
<p>
<label for="name">Name: </label>
<input type="text" name="name" id="name" value="${tagDTO.name}" />
<span class="error">#{error 'name' /}</span>
</p>
<p>
<label for="displayname">Displayname: </label>
<input type="text" name="displayname" id="displayname" value="${tagDTO.displayname}" />
<span class="error">#{error 'displayname' /}</span>
</p>
<p>
<input type="hidden" name="isnew" value="${tagDTO.isnew}" />
<input type="submit" value="Submit your comment" />
</p>
#{/form}
Now I could think of some ways to make it work, but none really elegant:
bind the form to the flash-object (or params-object) and populate the flas/params- object from the tagDTO
on validation-failure, refetch the tagDTO (not avail anymore so DB-call necessary) and overwrite values in tagDTO with values available in flash-object, bind form to tagDTO.
like 2, but using some sort of cache to quickly fetch tagDTO (so no need for db-call)
Some general mechanism to (de)serialize tagDTO from/to the session.
In short, I don't like any of them really. What would you consider to be a best practice in this situation? Or is there any functionality in the Play Framework that I'm missing?