Grails update instead of delete
Asked Answered
B

1

5

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() ]
}
Bowerman answered 7/1, 2012 at 9:4 Comment(0)
B
11

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 = {}
}
Billiton answered 7/1, 2012 at 9:41 Comment(9)
I like this solution, though I would also add a static property to the domain classes that I want this behavior on, and only override delete and list for classes that have the property set to true. That way you can still have instances of domain classes that really get deleted.Hourihan
good point. Also, it probably makes sense to create a new method like hardDelete on the domain classes that have the default delete method modified.Billiton
Good idea. also, rather than a static property as I mentioned above, just look for the existence of the deleted property. This could easily be turned into a Grails plugin. Call it soft-delete.Hourihan
@AnujArora If you happen to host it somewhere can you please post the link here?Bowerman
@AnujArora One question Anuj, will the list method work even when I change them in my controllers? For example my current app adds some criteria in default list method to do filtering by logged in user, in such a case will it automatically filter data by my criteria as well as deleteflag?Bowerman
@Grrrrr This will modify the static list method that is available for all domain classes. What criteria are you adding to your list method? Some code would be helpful.Billiton
@Grrrrr The list method that I've overridden in my answer is the list method of the domain class. However, you are calling the list method on the HibernateCriteriaBuilder (an instance of which is returned by the createCriteria method), which is entirely different. I would recommend modifying the criteria to include your deleted condition (you can also extend/modify the HibernateCriteriaBuilder class but it would require quite a bit of effort)Billiton
I like this solution, but there is a problem where this delete method will not work if a parameter is passed into it. ex. myObj.delete(flush:true) There is a second metaclass method that needs overriding. dc.clazz.metaClass.delete = { Map args -> ... will do the trick.Alexis
@Alexis Added requisite code. The solution is not really complete, as you would need to override other metaclass methods like list(Map args), find, criteria etc. as well to exclude deleted instances. But, it does outline a basic approach to go about it!Billiton

© 2022 - 2024 — McMap. All rights reserved.