Grails Controllers adding instances - grails

Alright I asked a question before but wasn't quite sure about it. So I went ahead and waited till now to ask again.
Main Question
How do I add a new instance of the domain through the controller? I created a function named gather to read a file with data and then create a new Book with the specific information, however it is not adding it to the database at all.
I currently have a controller (bookController) and the domain for it.
My domain is quite simple:
class Book {
static belongsTo = Author
String toString() { bookNumber }
Author bookAuthor
String title
static constraints = {
bookAuthor()
title()
}
}
I just 'generated' my views so I have the basic create, edit, list, and show. I went ahead and added my own inside the controller called gather. For the gsp, I just copied over the 'list.gsp' as I just want the user to view the list of books once the gather function is completed.
Here is what my controller looks like (just the basic generated one plus gather):
package bookdemo
import bookClient
class BookController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index = {
redirect(action: "list", params: params)
}
def gather = {
def w = new bookClient() //bookClient will gather books from txt files
def hosts = ["localhost"] //host to connect to
w.queryData(hosts) //grab information and parse
def abc = w.bookList //list of books
w.printData(abc) //print out list of books to make sure its not null
int numberOfBooks = abc.size() //list size
//create book list and return it
numberOfBooks.times {
def bookInstance = new Book(Author:"$abc.author", Title:"$abc.title")
return [bookInstance: bookInstance]
}
//params to show once adding books
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[bookInstanceList: book.list(params), bookInstanceTotal: book.count()]
}
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[bookInstanceList: book.list(params), bookInstanceTotal: book.count()]
}
def create = {
def bookInstance = new Book()
bookInstance.properties = params
return [bookInstance: bookInstance]
}
def save = {
def bookInstance = new Book(params)
if (bookInstance.save(flush: true)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])}"
redirect(action: "show", id: bookInstance.id)
}
else {
render(view: "create", model: [bookInstance: bookInstance])
}
}
def show = {
def bookInstance = book.get(params.id)
if (!bookInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "list")
}
else {
[bookInstance: bookInstance]
}
}
def edit = {
def bookInstance = book.get(params.id)
if (!bookInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "list")
}
else {
return [bookInstance: bookInstance]
}
}
def update = {
def bookInstance = book.get(params.id)
if (bookInstance) {
if (params.version) {
def version = params.version.toLong()
if (bookInstance.version > version) {
bookInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'book.label', default: 'Book')] as Object[], "Another user has updated this Book while you were editing")
render(view: "edit", model: [bookInstance: bookInstance])
return
}
}
bookInstance.properties = params
if (!bookInstance.hasErrors() && bookInstance.save(flush: true)) {
flash.message = "${message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), bookInstance.id])}"
redirect(action: "show", id: bookInstance.id)
}
else {
render(view: "edit", model: [bookInstance: bookInstance])
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "list")
}
}
def delete = {
def bookInstance = book.get(params.id)
if (bookInstance) {
try {
bookInstance.delete(flush: true)
flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "list")
}
catch (org.springframework.dao.DataIntegrityViolationException e) {
flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "show", id: params.id)
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])}"
redirect(action: "list")
}
}
}
The gsp shows up but for some reason my new books are not added. When I add a println in to test whether the information is in the list, it shows prints with the correct info. So I'm confused as to why it is not 'creating' the new book instance and adding it to the database.
Any suggestions?
Edit
Domain class for author:
class Author {
static hasMany = [books:Book]
String authorName
String notes
String toString() { authorName }
static constraints = {
machineName()
notes(maxSize:500)
}
}

You're not calling .save() on any of the Book instances...

I would suggets you write some unit tests for you controller and/or domain objects. Your objects cannot be being created successfully with this code
new Book(Author:"$abc.author", Title:"$abc.title")
Also the return statement here makes no sense
numberOfBooks.times {
def bookInstance = new Book(Author:"$abc.author", Title:"$abc.title")
return [bookInstance: bookInstance]
}
It looks like you have cut and pasted code without understanding what the code is doing. I think you want something more like this...
// iterate through the list of books and create the object array to pass back
def bookListInstance = []
w.bookList.each {
def bookInstance = new Book(Author:it.author, Title:it.title)
bookListInstance << bookInstance
}
// now return the list of domain objects
return [bookInstance: bookListInstance]

Related

Grails Controller Edit returns a map?

When I generate a controller for a domain class named User I get this code for the edit action:
def edit(Long id) {
def userInstance = User.get(id)
if (!userInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
redirect(action: "list")
return
}
[userInstance: userInstance]
}
Can someone please explain why this returns [userInstance: userInstance], rather thank just userInstance
Thank you!
The controller returns a map containing the data that you will (presumably) use in your view. The map keys are the names you use to this data from your view. Perhaps it would be a little less confusing if you renamed the map key, e.g.
def edit(Long id) {
def userInstance = User.get(id)
if (!userInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), id])
redirect(action: "list")
return
}
[user: userInstance]
}
To get the id of the User in your view, you would use:
${user.id}

Grails Mahout Plugin with Background Job (quartz2)

I am new in Grails. I am using Mahout Recommender Plugin for creating Recommender Engine. I am following this tutorial. It works fine for me.
Now What I am trying to do, I just want to do this Mahout Recommendation using Background JOB. So that User can recommendate automatically based on What they like. I am using Quartz 2.x Scheduler for Background Job purpose. How can I use Mahout as a Background JOB??
In this tutorial, You can see I have created one PrefrenceController.groovy where I am adding userID, itemID and prefrence number.
My Prefrence.groovy domain class file --
package com.rbramley.mahout
import org.apache.commons.lang.builder.HashCodeBuilder
class Preference implements Serializable {
long userId
long itemId
float prefValue
static constraints = {
userId()
itemId()
prefValue range: 0.0f..5.0f
}
boolean equals(other) {
if(!(other instanceof Preference)) {
return false
}
other.userId == userId && other.itemId == itemId
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append userId
builder.append itemId
builder.toHashCode()
}
static mapping = {
id composite: ['userId', 'itemId']
version false
}
}
and my PrefrenceController.groovy
package com.rbramley.mahout
import org.springframework.dao.DataIntegrityViolationException
class PreferenceController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def index() {
redirect(action: "list", params: params)
}
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
[preferenceInstanceList: Preference.list(params), preferenceInstanceTotal: Preference.count()]
}
def create() {
[preferenceInstance: new Preference(params)]
}
def save() {
def preferenceInstance = new Preference(params)
if (!preferenceInstance.save(flush: true)) {
render(view: "create", model: [preferenceInstance: preferenceInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'preference.label', default: 'Preference'), preferenceInstance.id])
redirect(action: "show", id: preferenceInstance.id)
}
def show(Long id) {
def preferenceInstance = Preference.get(id)
if (!preferenceInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "list")
return
}
[preferenceInstance: preferenceInstance]
}
def edit(Long id) {
def preferenceInstance = Preference.get(id)
if (!preferenceInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "list")
return
}
[preferenceInstance: preferenceInstance]
}
def update(Long id, Long version) {
def preferenceInstance = Preference.get(id)
if (!preferenceInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "list")
return
}
if (version != null) {
if (preferenceInstance.version > version) {
preferenceInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'preference.label', default: 'Preference')] as Object[],
"Another user has updated this Preference while you were editing")
render(view: "edit", model: [preferenceInstance: preferenceInstance])
return
}
}
preferenceInstance.properties = params
if (!preferenceInstance.save(flush: true)) {
render(view: "edit", model: [preferenceInstance: preferenceInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'preference.label', default: 'Preference'), preferenceInstance.id])
redirect(action: "show", id: preferenceInstance.id)
}
def delete(Long id) {
def preferenceInstance = Preference.get(id)
if (!preferenceInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "list")
return
}
try {
preferenceInstance.delete(flush: true)
flash.message = message(code: 'default.deleted.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "list")
}
catch (DataIntegrityViolationException e) {
flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'preference.label', default: 'Preference'), id])
redirect(action: "show", id: id)
}
}
}
Suppose I have added some data manually in my Database. Now When User click on RecommendController and put particular userID then It will show Recommendation. But I want to do this as a background Job. Recommendation should be suggest automatically to all users without any human intervention.
If I understood your question you need an on-demand job that you can run it from your controller. To do so create a job without any trigger, then you can trigger it manually from your Controller and pass into it your parameters. This will trigger the job on the background. In the execute define what the job needs to do, you can also inject any services that you need into that job.
Controller:
BackgroundJob.triggerNow([id:params.id,userId:userId])
Job
class BackgroundJob {
static triggers = {}
def execute(context) {
def id = context.mergedJobDataMap.get('id')
def userId = context.mergedJobDataMap.get('userId')
...
}
}

saving a second version of a grails object

one thing I would like to do is version the entries in our database. In my update method I would like to save a newer second version of an object. For instance
def update = {
def VariantInstance = Variant.get(params.id)
def NewVariantInstance = VariantInstance
NewVariantInstance.properties = params
if (VariantInstance) {
if (!VariantInstance.hasErrors()) {
VariantInstance.save()
NewVariantInstance.save()
flash.message = "${message(code: 'default.updated.message', args: [message(code: 'Variant.uniqueIdentifyingName', default: 'Variant'), VariantInstance.id])}"
redirect(action: "list")
}
else {
render(view: "edit", model: [VariantInstance: VariantInstance])
}
}
else {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'Variant.uniqueIdentifyingName', default: 'Variant'), params.id])}"
redirect(action: "list")
}
}
While this saves the current one, it does not create a new one. What am I doing wrong?
There's two problems; NewVariantInstance is going to just be a reference to the VariantInstance most likely, so it's dereferencing the same object. Additionally, when you do your params assignment you're also assigning the id field from VariantInstance to NewVariantInstance, so GORM will see the objects as the same when it does the save.

How can I redirect two actions instead of one action

here is my controller:
def save = {
def productNameInstance = new ProductName(params)
if (pharmacyMasterUpdateCompositeService.addProductName(productNameInstance)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'productName.label', default: 'ProductName'), productNameInstance.id])}"
redirect(action: "show", id: productNameInstance.id)
}
else {
render(view: "create", model: [productNameInstance: productNameInstance])
}
}
where addProductName(productNameInstance) is calling service that is defined in another class.
Here if you see redirecting is happening only at action :"show" if page is created.
My problem is how can i redirect two action like "show" and "print" at the same time where my "print" action downloads a pdf file ?
You can use the chain method.
def save = {
def productNameInstance = new ProductName(params)
if (pharmacyMasterUpdateCompositeService.addProductName(productNameInstance)) {
//...
chain(action: "print", params: [id: roductNameInstance.id])
}
else {
render(view: "create", model: [productNameInstance: productNameInstance])
}
def print = {
//...
chain(action: "show", params: params)
}
def show = { }
}

Getting error list from scaffolded function in Grails controller template

I'm using Grails 1.3.7. In a Grails project, I want to add a function ajaxupdate to the default scaffolded Controller, which does exactly the same job as the update function, but returns JSON data with the list of the eventual errors.
def ajaxupdate = {
String retMessage = ""
List errMessageList = []
def ${propertyName} = ${className}.get(params.id)
if (${propertyName}) {
${propertyName}.properties = params
if (!${propertyName}.hasErrors() && ${propertyName}.save(flush: true)) {
retMessage = "\${message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])}"
}
else {
// Add errors in errMessageList
}
}
else {
errMessageList.add("\${message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])}")
}
render(contentType: "text/json") {
answer(
message:retMessage,
errors:errMessageList)
}
}
If you're asking how to get the errors list, you can access Errors like
errMessageList = ${propertyName}.errors.allErrors.collect {g.message(error:it).encodeAsHTML()}

Resources