Grails update instead of delete - grails

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 = {}
}

Related

Update HasMany Relation in Grails Controller

I have the following grails domain classes:
A {
belongsTo = [b: B]
}
B {
hasMany = [aClasses: A]
}
In a GSP view I have a form where the user can select many A instances to connect them with a B instance. When the user submits the form the Controller which handles the form receives something like this:
params: [aClasses: [123,124]]
The user may have removed previously added aClasses from B so I tried to clear the aClasses of B first and then perform addTo but I get a java.util.ConcurrentModificationException.
Here is what I do in my Controller Action:
def update() {
B b = B.get(params.id)
b.properties = params
b.aClasses.clear()
def newAs = params.aClassIds ? [] + params.aClasses : []
newAs.each {
A a = A.get(it)
b.addToAClasses(a)
}
b.save(flush: true)
}
Is there a way to make this work?
Is this running in a service or controller? I've done something similar before but the logic was in a service and it worked. This kind of database access should run in a service because they are transactional.
The example that worked is :
if(!clone.hasErrors())
{
def projectTasks = Task.withCriteria {
project {
eq('id', project_id.toInteger())
}
}
projectTasks.each{ task ->
clone.addToTasks(task)
}
}
clone.save(flush : true)

How can I save a method for later, stubbing it for a period of time?

I'm writing a selenium-aid for a web application, and for one of the functions, I'm stubbing away the responses of a grails service. Is there any way to persist the methods for later, such that I can turn the service "back on"? The idea is that my test-aid code can be completely separated from production code, and no test-aids leak into the real service layer.
This works fine for turning the service "off", but getting it back on is an issue.
I'm doing this:
myService.metaClass.method1 = {true}
myService.metaClass.method2 = {false}
I tried just storing myService.metaClass.method1, but attempting to set it later just leaves the method stub.
How can I store method1 and method2 for later?
You can get a reference with getMetaMethod, e.g.
def oldMethod1 = MyService.metaClass.getMetaMethod('method1')
MyService.metaClass.method1 = { -> true }
def myService = ...
def realValue = oldMethod.invoke(myService)
This may not be the best way, but it is a way.
if (originalServiceMethods.isEmpty()) {
originalServiceMethods = myService.metaClass.getMethods()
}
myService.metaClass.invokeMethod = {name, args ->
def newMethods = [:]
newMethods["method1"] = {true}
newMethods["method2"] = {false}
if (name in newMethods.keySet()) {
return newMethods[name].call()
}
else {
return myService.metaClass.getMetaMethod(name, args)
}
}
...
if( !originalServiceMethods.isEmpty() ){
myService.metaClass.invokeMethod = {name, args ->
MetaMethod method = originalServiceMethods.find { it.name == name }
method.invoke(myService, args)
}
}

Grails: find domain class by name

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)

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.

Reading out all actions in a Grails-Controller

I need to read out all available actions from any controller in my web-app. The reason for this is an authorization system where I need to give users a list of allowed actions.
E.g.:
User xyz has the authorization for executing the actions show, list, search.
User admin has the authorization for executing the actions edit, delete etc.
I need to read out all actions from a controller. Does anyone has an idea?
This will create a List of Maps (the 'data' variable) with controller information. Each element in the List is a Map with keys 'controller', corresponding to the URL name of the controller (e.g. BookController -> 'book'), controllerName corresponding to the class name ('BookController'), and 'actions' corresponding to a List of action names for that controller:
import org.springframework.beans.BeanWrapper
import org.springframework.beans.PropertyAccessorFactory
def data = []
for (controller in grailsApplication.controllerClasses) {
def controllerInfo = [:]
controllerInfo.controller = controller.logicalPropertyName
controllerInfo.controllerName = controller.fullName
List actions = []
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(controller.newInstance())
for (pd in beanWrapper.propertyDescriptors) {
String closureClassName = controller.getPropertyOrStaticPropertyOrFieldValue(pd.name, Closure)?.class?.name
if (closureClassName) actions << pd.name
}
controllerInfo.actions = actions.sort()
data << controllerInfo
}
Here's an example that works with Grails 2, i.e it will capture actions defined as either methods or closures
import org.codehaus.groovy.grails.commons.DefaultGrailsControllerClass
import java.lang.reflect.Method
import grails.web.Action
// keys are logical controller names, values are list of action names
// that belong to that controller
def controllerActionNames = [:]
grailsApplication.controllerClasses.each { DefaultGrailsControllerClass controller ->
Class controllerClass = controller.clazz
// skip controllers in plugins
if (controllerClass.name.startsWith('com.mycompany')) {
String logicalControllerName = controller.logicalPropertyName
// get the actions defined as methods (Grails 2)
controllerClass.methods.each { Method method ->
if (method.getAnnotation(Action)) {
def actions = controllerActionNames[logicalControllerName] ?: []
actions << method.name
controllerActionNames[logicalControllerName] = actions
}
}
}
}
Grails does not support a straightforward way to do this. However, I was able to put together a puzzle from available grails methods and have come to this solution:
def actions = new HashSet<String>()
def controllerClass = grailsApplication.getArtefactInfo(ControllerArtefactHandler.TYPE)
.getGrailsClassByLogicalPropertyName(controllerName)
for (String uri : controllerClass.uris ) {
actions.add(controllerClass.getMethodActionName(uri) )
}
Variables grailsApplication and controllerName are injected by grails.
As controller itself does not have necessary methods, this code retrieves its controllerClass (see GrailsControllerClass), which has what we need: property uris and method getMethodActionName
To print out a list of all the methods with action names:
grailsApplication.controllerClasses.each {
it.getURIs().each {uri ->
println "${it.logicalPropertyName}.${it.getMethodActionName(uri)}"
}
}
I had to pull a list of all controllers and their respective URI. This is what I did on a grails 3.1.6 application.
grailsApplication.controllerClasses.each { controllerArtefact ->
def controllerClass = controllerArtefact.getClazz()
def actions = controllerArtefact.getActions()
actions?.each{action->
def controllerArtefactString = controllerArtefact.toString()
def controllerOnly = controllerArtefactString.split('Artefact > ')[1]
println "$controllerOnly >>>> $controllerOnly/${action.toString()}"
}
}

Resources