Render Errors From A Service - grails

I call a service that creates a parent and a child record. If an error happens, the service throws a RuntimeException. The RuntimeExceptionis is caught by the controller and then there there is a redirect back to the gsp. But the error is not being rendered.
In this case, I guess the controller and thus the gsp doesn't really no anything about the objects, since everything is done in the service. So how do I render the errors?
Simple Data Entry GSP
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sample title</title>
</head>
<body>
<h1>Add A Record</h1>
<g:hasErrors bean="${parent}">
<div class="errors">
<g:renderErrors bean="${parent}" as="list" />
</div>
</g:hasErrors>
<g:hasErrors bean="${child}">
<div class="errors">
<g:renderErrors bean="${child}" as="list" />
</div>
</g:hasErrors>
<g:form action="add" name="doAdd">
<table>
<tr>
<td>
Parent Name
</td>
<td>
Child Name
</td>
</tr>
<tr>
<td>
<g:textField name="parentName" />
</td>
<td>
<g:textField name="childName" />
</td>
</tr>
<tr><td><g:submitButton name="update" value="Update" /></td></tr>
</table>
</g:form>
</body>
</html>
Controller
class AddrecordController {
def addRecordsService
def index = {
redirect action:"show", params:params
}
def add = {
println "do add"
try {
addRecordsService.addAll(params)
} catch (java.lang.RuntimeException re){
println re.message
flash.message = re.message
}
redirect action:"show", params:params
}
def show = {}
}
Service
class AddRecordsService {
static transactional = true
def addAll(params) {
def Parent theParent = addParent(params.parentName)
def Child theChild = addChild(params.childName,theParent)
}
def addParent(pName) {
def theParent = new Parent(name:pName)
if(!theParent.save()){
throw new RuntimeException('unable to save parent')
}
return theParent
}
def addChild(cName,Parent theParent) {
def theChild = new Child(name:cName,parent:theParent)
if(!theChild.save()){
throw new RuntimeException('unable to save child')
}
return theChild
}
}

You need to get a reference to the invalid object somehow and pass it to the view via the model so I would extend RuntimeException and add fields to contain the objects with validation errors e.g.
}catch(MyCustomException m){
render view:'show', model:[parent:m.getParent(), child:m.getChild()]
}
This whole exercise might be easier using Parent.withTransaction instead of the automatic rollback via RuntimeExceptions. Then you could manually rollback the transaction if there's validation errors and just return the objects instead of having to contain them in the exception.

Related

List of domain contents not rendering on one GSP but is on another Grails

Right so my codes for my test view is:
#Secured(["IS_AUTHENTICATED_REMEMBERED", "IS_AUTHENTICATED_FULLY"])
def list(){
def allPosts = postService.getPosts()
}
<body>
<h1>Welcome to the main feed, <sec:loggedInUserInfo field="username" var="username"/></h2>
<g:if test="${flash.message}">
<div class="messageContainer">
<div style="display: block">${flash.message}</div>
</div>
</g:if>
<p/>
<div>
<g:each var="post" in="${allPosts}">
<p>Last Name: ${post.content}</p>
<p>First Name: ${post.content}</p>
</g:each>
</div>
</body>
</html>
And this works,
This was just to test if there was another issue though as what I want it to work on is this:
#Secured(["IS_AUTHENTICATED_REMEMBERED", "IS_AUTHENTICATED_FULLY"])
def wall() {
def allPosts = postService.getPosts()
profile = springSecurityService.currentUser.getProfile()
if(!profile){
redirect(controller: "profile", action: "viewProfile")
}else {
[profile: profile]
}
}
and
<!doctype html>
<html>
<head>
<meta name="layout" content="main"/>
</head>
<body>
<h1>Welcome to the main feed, <sec:loggedInUserInfo field="username" var="username"/></h2>
<g:if test="${flash.message}">
<div class="messageContainer">
<div style="display: block">${flash.message}</div>
</div>
</g:if>
<p/>
<div>
<h3>
What are you thinking?
</h3>
</p>
<div>
<g:form action="addPost">
<g:textArea class="postContent" id="postContent" name="content" rows="3" cols="50"/><br/>
<g:submitButton class="postSubmit loginButton" name="post" value="Post"/>
</g:form>
<div>
</div><br/>
<div class="PostContainer">
<g:each var="post" in="${allPosts}">
<p>${post.content}</p>
<p>${post.content}</p>
</g:each>
</div>
</div>
</body>
</html>
but the posts and content will not render on the second example
also the postService:
#Transactional
class PostService {
def getPosts() {
[allPosts:Post.list()]
}
}
Any insight into this would be greatly appreciated.
I am using windows 10 and chrome for the browser
Try to return from the service in this way
#Transactional
class PostService {
def getPosts() {
Post.list()
}
}

Grails- groovy sql each row to be displayed in gsp view

I want to display the result of sql each row from the service code to my gsp view.
My Service code is:
def health()
{
def schemaList = [:]
groovy.sql.Sql sql = new groovy.sql.Sql(dataSource);
sql.eachRow("SELECT SOURCE, count(1) as COUNT from fact group by SOURCE");
ArrayList returnResults = []
sqlStatement.eachRow(sqlString)
{
returnResults<<it.toRowResults()
}
sqlStatement.close()
return[returnMap:returnResults]
}
My Controller Code is:
def stats = {
def health = AccessLogService.heath()
render (template:'healthview', model:[health:health])
}
My gsp view is as follows:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="admin" />
<title>Health</title>
</head>
<body>
<SCRIPT language="JavaScript">
</SCRIPT>
<br />
<br />
<font style='font-size:14px;font-weight:bold;'>Health Condition</font>
<div id='overall'>
<g:if test="${health.size() > 0}">
<table border="1">
<thead>
<tr>
<th>Source</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<g:each in="${health}" status="i" var="thisRecord">
<tr>
<td>${thisRecord.SOURCE}</td>
<td>${thisRecord.COUNT}</td>
</tr>
</g:each>
</tbody>
</table>
</g:if>
</div>
</body>
</html>
I am not able to see the results of my query in gsp view? Where I am going wrong.
you are trying to get the wrong key of your model.
you service returns a hash [returnMap:returnResults] so your controller renders the model: [health:health] -> [health:[returnMap:returnResults]].
thus in your gsp you should refer to health.returnMap to see the list:
<g:if test="${health.returnMap}">
...
<g:each in="${health.returnMap}" status="i" var="thisRecord">
<tr>
<td>${thisRecord.SOURCE}</td>
<td>${thisRecord.COUNT}</td>
</tr>
</g:each>
...
</g:if>
UPDATE:
the code looks strange... this is how it should be:
ArrayList returnResults = []
sql.eachRow("SELECT SOURCE, count(1) as COUNT from fact group by SOURCE"){
returnResults << it.toRowResults()
}
Where is the sqlStatement variable declared in your service? I think that is the error.
And an advice you need to debug your program. for example, Test if the service returns result by:
running your app debug mode
using log.debug
using println
or if you are doing these and have seen any erorrs on your console post that here.

How to keep query results after deleting an item?

In my Grails application I have multiple pages that list a group of data objects inside of a table. In these pages I provide a search function which when performed will adjust the table to only display the data objects that match the query. However If a user decides to delete one of these data objects the application will take them back to the default table which displays everything. I would like for query results to remain intact after performing a delete.
I will use my "Skill Evaluations" page as my example in this post.
Here is the relevant code in the domain class
SkillEval.groovy
class SkillEval {
static hasMany = [lines: SkillEvalL, courses: CourseOffering, choiceLabels: ChoiceLabel]
String name
String formVersion
static def search(params) {
def criteria = SkillEval.createCriteria()
def results = criteria.list(params) {
or {
ilike("name", params.search+'%')
}
}
return results
}
}
Relevant section of the gsp view file
list.gsp
<g:form>
<div class="search">
<label for="searchField">Search:</label> <input type="text"
id="searchField" name="search" value="${params.search}" /> <input
type="submit" value="Search" />
</div>
<br>
<table id="mainTable">
<thead>
<tr>
<th>Name</th>
<th>Version</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<g:each var="eval" in="${skillEvalList}">
<tr>
<td>
<strong>
${eval.name}
</strong>
</td>
<td>
${eval.formVersion}
</td>
<td>
<g:actionSubmit value="Delete" controller="skillEval" action="delete" onclick="setId(${eval.id});return confirm('Are you sure?');" class="delete" />
</td>
</tr>
</g:each>
</tbody>
</table>
<g:if test="${(skillEvalCount/maxCount) > 1}">
<div class="pagination">
<g:paginate action="list" total="${skillEvalCount}" />
</div>
</g:if>
<input id="evalId" type="hidden" name="id" value="" />
</g:form>
</div>
<r:script>
function setId(id)
{
$('#evalId').val(id);
}
</r:script>
Relevant code in the Controller class
SkillEvalController.groovy
def delete(Long id) {
def skillEval = SkillEval.get(id)
if (skillEval) {
def allInstances = SkillEvalI.findAllByForm(skillEval)
allInstances.each { evalInstance ->
evalInstance.lines.clear()
if(!evalInstance.delete()) {
println "Failed to delete skill eval instance"
}
else {
println "Instance successfully deleted."
}
}
try {
skillEval.delete(flush: true)
}
catch (DataIntegrityViolationException e) {
}
}
redirect(action: "list")
}
How can I make the view retain the queried results after deleting one of the queried items?
When you redirect to the list action you can provide parameters -- just capture the parameters (if any) in the delete action and pass them in the redirect call to list at the end of the controller action.
(Update: Forgot that actionSubmit does not accept params as an attribute, so cobbled together this solution from this SO answer and the Grails docs)
Example:
// View (list.gsp)
<g:actionSubmit action="deleteWithParams" value="Delete" ... />
// Controller
def list() {
def deleteWithParams = { forward(action:'delete', params:[search: params?.search]) }
render...
}
def delete(Long id) {
// Deleting the skillEval ...
redirect(action: "list", params: [search: params?.search])
}

How can I send an email with a layout

I am using grails mail plugin. When I submit my form, it will send an email from aaa#example.com to textField name="email successfully but how can I send an email with a layout...not blank like this picture http://www.4shared.com/photo/uT2YUCfo/Capture__2_.html or maybe some CSS..
FORM
<g:form action="send">
<table style="width:500px">
<tbody>
<tr>
<td>Your Email Address </td>
<td><g:textField style="width:250px" name = "email"/></td>
</tr>
<tr>
<td>Your Name</td>
<td><g:textField style="width:250px" name = "user"/></td>
</tr>
<tr>
<td><input type="submit"/></td>
</tr>
</tbody>
</table>
</g:form>
MAIL CLOSURE
def send = {
sendMail {
to params.email
from "aaa#yahoo.com"
subject "Test Reset Password"
body(view:"/user/layoutmail",model:[name:params.user])
}
render "Email Terkirim"
}
Well you could actually use a layout for emails, similarly how you would use layouts for view pages. What you would want to do is create a new layout and a view file for your email body content.
Layout: eg. ../views/layouts/emailLayout.gsp
<%# page contentType="text/html" %>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
a {color: #348eda;}
</style>
</head>
<body>
<g:layoutBody/>
</body>
</html>
View eg. ../views/emails/welcomeEmail.gsp
<%# page contentType="text/html" %>
<g:applyLayout name="emailLayout">
<html>
<body
Your Welcome ${welcome.username}
</body>
</html>
</g:applyLayout>
And to send the mail heres an example
def sendWelcomeMail(User user, String url){
def rtn = [success:false]
if(user) {
def fooBar = [
username: user.username,
email: user.email,
url: url
]
sendMail {
async true
to fooBar.email.trim()
subject "Welcome Email"
body(view: '/emails/welcomeEmail', model: [welcome: fooBar])
}
rtn.success = true
}
return rtn
}
It isn't going to pick up a grails layout. And you don't really want it to. You should construct your email in a fashion that it could be a stand alone web page with no other dependencies. All the static resources used should be accessible via a public URL.

user-defined form validation in grails

I am learning grails by doing some sample programs.
I want to know how to validate a user-defined form using grails.
My code is:
Domain class
class User
{
String property
static constraints =
{
property(blank:false,nullable:false)
}
}
Controller class
def addUser() {
}
def userPrint() {
def values = request.getParameterValues("property")
for(val in values){
println "values received :"+val
}
}
addUser.gsp
<html>
<head>
<title>Users</title>
</head>
<body>
<g:form name="useraddform" url="[controller:'user',action:'userPrint']">
<table>
<tr>
<td>Username :</td>
<td><g:textField name="property" value=""/></td>
</tr>
<tr>
<td>Password : </td>
<td><g:textField name="property" value=""/></td>
</tr>
</table>
<input type="submit" value="ADD"/>
</g:form>
</body>
</html>
I need to validate the username and password entered.
How to achieve this???
Please help....!
Please read the constraints manual section and whole web layer chapter.
Also, run grails generate-all on some other sample project and look at scaffolding GSPs contents, especially hasErrors tag/function.

Resources