Grails Issue with ShoppingCart plugin - grails

I'm trying to use the Grails shopping cart plugin found here: http://grails.org/plugin/shopping-cart
I was able to successfully install the plugin in my application, as well as inject the service in my Controller:
class TestController {
def shoppingCartService
def index() {
def s = new DomainObj(name: "A Plain Ole Domain Object")
s.addToShoppingCart()
}
}
This appears to be adding the product to my shopping cart, as I expected. However, the problem I'm encountering now is actually listing the items out from the cart. According to the debugger, after running the above code, the shopping cart does indeed have an item (s) in it, as it returns:
com.metasieve.shoppingcart.ShoppingItem : 1
The item is properly being added to the cart, but now I would like to actually list the name of the item out again, so in this case, I want to display the name A Plain Ole Domain Object. How do I do this?
I'm unsure of the syntax for getting the actual objects back from the cart. The documentation doesn't describe how to do this clearly, as it merely states that the following should work:
def checkedOutItems = shoppingCartService.checkOut()
checkedOutItems.each {
println it['item']
println it['qty']
}
But that outputs
com.metasieve.shoppingcart.ShoppingItem : 1 , which is only a reference to some arbitrary item in the cart. I want to get back the actual name of my item.
Thanks in advance.
EDIT:
My domain class (DomainObj) is defined as follows:
class DomainObj extends com.metasieve.shoppingcart.Shoppable {
String name
static constraints = {
name blank: false
}
}
EDIT #2:
def index() {
def s = new DomainObj(name: "A Plain Ole Domain Object")
s.addToShoppingCart()
def r = new DomainObj(name: "Second Plain Ole Domain Object")
r.addToShoppingCart()
def checkedOutItems = shoppingCartService.checkOut()
println currentItems
println "-----"
checkedOutItems.each {
println it['item']
println it['qty']
}
}
The output of this is:
[com.metasieve.shoppingcart.ShoppingItem : 1, com.metasieve.shoppingcart.ShoppingItem : 2]
com.metasieve.shoppingcart.ShoppingItem : 2
1
com.metasieve.shoppingcart.ShoppingItem : 1
1

According to the documentation it["item"] gives you back the entity of a domain class that extends Shoppable. So in this case when you are printing it out it's calling the toString() method of that domain class. If you want that to return the value of the name property you need to implement your own toString(). Here is such an example
#Override
String toString() {
return name
}
EDIT:
Well as it's not clear from the documentation it['item'] is a pointer to the Shoppable instance which you can then use to query for the actual product in your cart like this:
com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
Thus the following will print out the toString() value of your products
checkedOutItems.each {
println com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
println it['qty']
}
For testing I created the following domain and controller.
Domain:
package com.test
class MyProduct extends com.metasieve.shoppingcart.Shoppable {
String name
static constraints = {
name(blank: false)
}
#Override
String toString() {
return name
}
}
Controller:
package com.test
class MyProductController {
def shoppingCartService
def index() {
def p1 = new MyProduct(name: 'one')
p1.save(flush: true, failOnError: true)
p1.addToShoppingCart()
def p2 = new MyProduct(name: 'two')
p2.save(flush: true, failOnError: true)
p2.addToShoppingCart()
def checkedOutItems = shoppingCartService.checkOut()
checkedOutItems.each {
println com.metasieve.shoppingcart.Shoppable.findByShoppingItem(it['item'])
println it['qty']
}
}
}

Related

Grails enum as domain property intermittently saving as ordinal value in database

Grails 2.3.7, Java 1.7, tomcat
For no apparent reason(that I can see) the reviewResults property of the Review domain sometimes saves as the ordinal value of the enum.
The database schema says that the column is a varchar type.
Sometimes NA is saved as NA, however, sometimes it is saved as 0.
This is the same with passed, except passed is saved as 1 sometimes.
Any ideas why this might be happening?
abstract class Work {
// Nothing defined in here related
// to the review domain enum.
}
The Domain class in question.
class Review extends Work {
Results reviewResults
String notes
enum Results {
NA,
Passed,
Error
}
static constraints = {
reviewResults(nullable: true, enumType: 'string')
}
// Is this redundant if it is already declared in the constraints?
static mapping = {
reviewResults enumType: 'string'
}
}
The Domains related controller.
// Reviews created with Quartz job, results property is not set.
class ReviewController {
def reviewService
def show(Long id) {
def reviewInstance = Review.get(id)
def reviewResultsOptions = []
reviewResultsOptions.addAll(com.mycompany.app.Review.Results.values())
[reviewInstance: reviewInstance, reviewResultsOptions: reviewResultsOptions]
}
def closeWork(Long id, String reviewResults, String notes) {
def review = Review.get(id)
review.reviewResults = Review.Results.valueOf(reviewResults)
def result = reviewService.closeReview(review, notes)
}
}
The service for the controller/domain.
class ReviewService {
def workService
Review closeReview(Review work, String notes) {
work.notes = notes
workService.closeWork(work)
return work.errors.allErrors.empty ? work : null
}
}
The service where the Review object is finally saved.
class WorkService {
Tracking closeWork(Work workInstance) {
def tracked = new Tracking()
workInstance.setStatus(status)
workIntance.setClosed(new Date())
WorkInstance.save(flush: true)
// Set some tracking properties and save and return the tracking object.
}
}

Why values of list is changing while sending to a service

I am new with grails and am developing a web application.
I have a List of long values which is getting from ids of Domain class objects.
Initially this List is like [1,2,3]. I need to use this list of values in my service class for saving the associations.
But the same List is getting in service class as [49,50,51]
Why this difference of 48 is occurred? and how can i get the List as same as i sent.
Controller class:
def createQuestion(CreateQuestionCommand createQuestionCmd) {
if( createQuestionCmd.hasErrors() ) {
render(view:"create_question", model:[createQuestionCmd:createQuestionCmd , tags:Tag.list()])
} else {
Question question = new Question()
question.title=createQuestionCmd.title
question.description=createQuestionCmd.description
List tags= createQuestionCmd.tags
question = questionService.create(question,tags)
render(view: "question_submitted")
}
}
service class:
def create(Question question, List<Long> tagId) {
List<Tag> tagList=getTagsById(tagId)
question.save( failOnError:true )
Iterator itr=tagList.iterator();
while(itr.hasNext()) {
Tag tag=itr.next()
question.addToTags(tag).save()
}
}
def getTagsById(List tagId){
Iterator itr=tagId.iterator();
List<Tag> tags
while(itr.hasNext()) {
long id=itr.next()
println "value of id is : "
println id
println id.getClass().getName()
Tag tag=Tag.findById(id)
tags.add(tag)
}
return tags
}
CreateQuestionCmd.tags are List<String> and you are trying to place that to List<Long>
Just pass the object to service and create question object.In groovy we create the object in map format.In java only, we need iterator to loop collection.In groovy we use each closure to loop the collection. Try it will work out. Any problem in the following code let me know.I will help.
Controller class:
def createQuestion(CreateQuestionCommand createQuestionCmd) {
if(createQuestionCmd.hasErrors() ) {
render(view:"create_question", model:[createQuestionCmd:createQuestionCmd , tags:Tag.list()])
} else {
questionService.create(createQuestionCmd)
render(view: "question_submitted")
}
}
service class:
def create(def createQuestionCmd) {
def question = new Question(title:createQuestionCmd.title,description:createQuestionCmd.description)
question.save(flush:true)
List tagIds= createQuestionCmd.tags
tagIds.each{
def tag=Tag.findById(id)
question.addToTags(tag).save(flush:true)
}
}

How to write constraints for hasMany properties in grails

I have three classes in grails application
class Category {
String name
}
class Application {
String name
static hasMany =[specialCategoryies:SpecialCategory]
}
class SpecialCategory {
Category category
Integer points
static belongsTo =[application:Application]
}
Here while I am saving the applicationInstance I don't want save duplicate
specialCategories values like ..specialCategories does not have same
category value again ..
application.addToSpecialCategoryies(newSpecialCategory(category:Category.get(1),points:2))
application.addToSpecialCategoryies(newSpecialCategory(category:Category.get(1),points:3))
here i application instance should rise error that category value repeated..
so how define constraints for hasMany properties in domain class......?
suggest how to write constraints to avoid duplicate values of category
You might try using a custom validator in your Application constraints section. For example, one way to check for duplicate property values is to collect the values into an array and compare them to the corresponding unique array (with duplicated elements removed):
class Application {
String name
static hasMany =[specialCategoryies:SpecialCategory]
static constraints = {
specialCategoryies validator: { specialCategories, obj ->
def specialCategoriesIdArray = specialCategories.collect {it?.category?.getId()}
return (specialCategoriesIdArray.size() == specialCategoriesIdArray.unique().size())?true:'application.validator.specialcategoryduplicate.error'
}
}
}
When trying to save a special category with an existing category, it will throw a validation error when saving. You can test with the following:
def cat1 = new Category(name:"Cat 1").save(flush:true)
def cat2 = new Category(name:"Cat 2").save(flush:true)
def app = new Application()
app.name = "Test"
app.addToSpecialCategoryies(new SpecialCategory(category: Category.get(1), points:2))
app.addToSpecialCategoryies(new SpecialCategory(category: Category.get(2), points:2))
app.addToSpecialCategoryies(new SpecialCategory(category: Category.get(1), points:3))
if ( app.save(flush:true) ){
log.info "Saved!"
} else {
log.error "NOT Saved. Error:"
app.errors.each {
log.error it
}
}

Grails: querying hasMany association

I know there are several questions on this subject but none of them seem to work for me. I have a Grails app with the following Domain objects:
class Tag {
String name
}
class SystemTag extends Tag {
// Will have additional properties here...just placeholder for now
}
class Location {
String name
Set<Tag> tags = []
static hasMany = [tags: Tag]
}
I am trying to query for all Location objects that have been tagged by 1 or more tags:
class LocationQueryTests {
#Test
public void testTagsQuery() {
def tag = new SystemTag(name: "My Locations").save(failOnError: true)
def locationNames = ["L1","L2","L3","L4","L5"]
def locations = []
locationNames.each {
locations << new Location(name: it).save(failOnError: true)
}
(2..4).each {
locations[it].tags << tag
locations[it].save(failOnError: true)
}
def results = Location.withCriteria {
tags {
'in'('name', [tag.name])
}
}
assertEquals(3, results.size()) // Returning 0 results
}
}
I have validated that the data is being created/setup correctly...5 Location objects created and the last 3 of them are tagged.
I don't see what's wrong with the above query. I would really like to stay away from HQL and I believe that should be possible here.
Welcome to hibernate.
The save method informs the persistence context that an instance should be saved or updated. The object will not be persisted immediately unless the flush argument is used
if you do not use flush it does the saves in batches so when you setup your query right after the save it appears that the data is not there.
you need to add
locations[it].save(failOnError: true, flush:true)
You should use addTo* for adds a domain class relationship for one-to-many or many-to-many relationship.
(2..4).each {
locations[it].addToTags(tag)
}

Better way to discover relationship dynamically when saving a new record? (otherSide fails)

Given this relationship:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static belongsTo = [a:A]
}
I have an record b that I want to save. I've already discovered via working Grails reflection (omitted in the code example below) that it needs to be an instance of class B. Beyond that, record b only knows:
it has a relation "a"
relation "a"'s key
Since it's a dynamic case, we do not know and must discover:
relation "a" is to an instance of class A (so we can call A.find(a's key))
the "other side" of the relation - class A's perspective - is relation "b" (so we can call .addToB(b))
So how do I save b to the database? Here's how I'm doing it:
class AssocTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
// I don't know this part, but it's in the DB
def a = new A(name:"al")
a.save()
}
void testAssociation() {
// I want to create a new B such that name="bob"
// I also had to discover "class B" using (working) Grails reflection
// but omitted it for this example.
def b = new B(name:"bob")
// ... and the relation is as "given" below
def given = [a:[name:"al"]]
// So I need to call A.find([name:"al"]).addToB(b). But "A" and
// "addToB" are unknown so need to be found via reflection
def gdc = new DefaultGrailsDomainClass(B)
given.each { give ->
def prop = gdc.getPropertyByName(give.key)
if (prop.isAssociation() && !prop.isOwningSide()) {
println "I want to use otherSide, but it's ${prop.otherSide}"
def os = reallyGetOtherSide(B, give)
def object = os.parent.find(
os.parent.newInstance(give.value))
object."${os.method}"(b)
}
}
def bFound = B.findByName("bob")
assertEquals "al", bFound.a.name
}
def reallyGetOtherSide(clazz, relation) {
def parent=clazz.belongsTo[relation.key]
def addTo=parent.hasMany.find { (clazz == it.value) }.key
[parent:parent, method:"addTo${addTo.capitalize()}"]
}
}
...with otherSide returning null, unfortunately. This can't be the best way to do this, can it?
If I understood you correctly, You can refer to these docs here. You can try the following:
`new A(name:"Gatwick")
.addToB(new B(name:"BA3430"))
.addToB(new B(name:"EZ0938"))
.save()`

Resources