Grails: find domain class by name - grails

I want to allow users to traverse the domain classes and print out dumps of stuff. My frist problem: assuming the following works just fine:
//this works
class EasyStuffController{
def quickStuff = {
def findAThing = MyDomainClass.findByStuff(params.stuff)
[foundThing:findAThing]
}
}
What is the proper way to write what I am trying to say below:
//this doesn't
class EasyStuffController{ servletContext ->
def quickStuff = {
def classNameString = "MyDomainClass" //or params.whichOne something like that
def domainHandle = grailsApplication.domainClasses.findByFullName(classNameString)
//no such property findByFullName
def findAThing = domainHandle.findByStuff(params.stuff)
[foundThing:findAThing]
}
}
//this also doesn't
class EasyStuffController{ servletContext ->
def quickStuff = {
def classNameString = "MyDomainClass" //or params.whichOne something like that
def domainHandle
grailsApplication.domainClasses.each{
if(it.fullName==classNameString)domainHandle=it
}
def findAThing = domainHandle.findByStuff(params.stuff)
//No signature of method: org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass.list() is applicable
[foundThing:findAThing]
}
}
Those lines above don't work at all. I am trying to give users the ability to choose any domain class and get back the thing with "stuff." Assumption: all domain classes have a Stuff field of the same type.

If you know the full package, you can use this:
String className = "com.foo.bar.MyDomainClass"
Class clazz = grailsApplication.getDomainClass(className).clazz
def findAThing = clazz.findByStuff(params.stuff)
That will also work if you don't use packages.
If you use packages but users will only be providing the class name without the package, and names are unique across all packages, then you can use this:
String className = "MyDomainClass"
Class clazz = grailsApplication.domainClasses.find { it.clazz.simpleName == className }.clazz
def findAThing = clazz.findByStuff(params.stuff)

Related

Pass value from grails controller to a class inside src/groovy

I have a Grails application. I want to use a value from Grails controller class (say MyController) inside a class in src/groovy/MyClass.groovy
How can I pass the value from Grails controller class to this class? I couldn't find anything relevant.
I tried this:
class MyController {
def name = "myapp"
}
Class MyClass{
def username = MyController.name
}
Please correct me . Thanks
It is hard to say for sure without knowing what you are doing but your probably want to pass the value as an argument to a method in MyClass and you probably don't want the value to be a field in the controller class.
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass()
mc.someMethod(name)
// ...
}
}
class MyClass {
def someMethod(String name) {
// do whatever you want to do with the name
}
}
Or you could pass the value as a constructor argument:
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass(name: name)
// ...
}
}
class MyClass {
def name
}
I hope that helps.

How to add default values to hasMany in Grails?

Say I have a domain Books.
static hasMany = [reader:Reader]
And Class Reader
String fullName
Now I want to add Readers with fullName: "PersonA", "PersonB", "PersonC" by defualt in the Books domain.
Please tell how do I accomplish this? I am pretty new with Grails.
You can create class named BootStrap in Configuration folder of your App andd add init() method to it. This method will be executed before App starts. Example:
class BootStrap {
def init() {
def readerA = Reader.findOrCreateByFullName("PersonA")
def readerB = Reader.findOrCreateByFullName("PersonB")
def readerC = Reader.findOrCreateByFullName("PersonC")
def readers = [readerA, readerB, readerC]
def book = new Book()
for(reader in readers){
book.addToReader(reader)
}
book.save(flush: true)
}
}

Grails update instead of delete

Is there an easy way in Grails to not allow deleting for any Domain Class? And rather have a delete flag in each domain which gets updated whenever something is deleted.
Also, in effect all the list/show methods should not show objects where delete flag is true.
I know I can do that by manually editing all my CRUD methods in all the controllers but that seems a little bit too much work when working with Grails where everything can be done by changing some flag somewhere!!
My usual list method looks like following, almost all the list methods in my project lets user access things which only belongs to users' company.
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
def documentsList = Documents.createCriteria().list(params){
eq("company.id",session.companyId)
maxResults(params.max)
order("dateCreated","desc")
//firstResult(params.offset)
}
[documentsInstanceList: documentsList , documentsInstanceTotal: documentsList.getTotalCount() ]
}
You'll have to ovveride the delete and list methods of all your domain classes. Add code like this to your Bootstrap
class BootStrap {
def grailsApplication
def init = { servletContext ->
for (dc in grailsApplication.domainClasses) {
dc.clazz.exists(-1); //to register meta class
def gormSave = dc.clazz.metaClass.getMetaMethod('save');
dc.clazz.metaClass.delete = { ->
delegate.deleted = true
gormSave.invoke delegate
}
dc.clazz.metaClass.delete = { Map args ->
delegate.deleted = true
gormSave.invoke(delegate, args)
}
dc.clazz.metaClass.static.list = { ->
def crit = delegate.createCriteria();
def list = crit.list{
eq('deleted', false)
}
return list;
}
}
}
def destroy = {}
}

custom Grails validation

Normally for a Grails domain or command class, you declare your constraints and the framework adds a validate() method that checks whether each of these constraints is valid for the current instance e.g.
class Adult {
String name
Integer age
void preValidate() {
// Implementation omitted
}
static constraints = {
name(blank: false)
age(min: 18)
}
}
def p = new Person(name: 'bob', age: 21)
p.validate()
In my case I want to make sure that preValidate is always executed before the class is validated. I could achieve this by adding a method
def customValidate() {
preValidate()
validate()
}
But then everyone who uses this class needs to remember to call customValidate instead of validate. I can't do this either
def validate() {
preValidate()
super.validate()
}
Because validate is not a method of the parent class (it's added by metaprogramming). Is there another way to achieve my goal?
You should be able to accomplish this by using your own version of validate on the metaclass, when your domain/command class has a preValidate() method. Something similar to the below code in your BootStrap.groovy could work for you:
class BootStrap {
def grailsApplication // Set via dependency injection
def init = { servletContext ->
for (artefactClass in grailsApplication.allArtefacts) {
def origValidate = artefactClass.metaClass.getMetaMethod('validate', [] as Class[])
if (!origValidate) {
continue
}
def preValidateMethod = artefactClass.metaClass.getMetaMethod('preValidate', [] as Class[])
if (!preValidateMethod) {
continue
}
artefactClass.metaClass.validate = {
preValidateMethod.invoke(delegate)
origValidate.invoke(delegate)
}
}
}
def destroy = {
}
}
You may be able to accomplish your goal using the beforeValidate() event. It's described in the 1.3.6 Release Notes.

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