Search code examples
grailsgrails-2.0grails-plugingrails-domain-classgrails-controller

Grails simple-blog BlogEntry class how to use FindByTagAndLockedAndPublish in one short


I am using simple-blog plugin in grails. i have code

class OodlesBlogEntry extends org.grails.blog.BlogEntry implements Taggable, Commentable{

Boolean isProtected = false;

}


  def entries =  OodlesBlogEntry.findAllByTag(params.tag.trim(), [max:5, offset:params.offset, sort:"dateCreated", order:"desc"])

And

entries.findAll { it.published }

these are working fine but the problem is i want to use both statement together so that it can give me perfect output. something like.

def entries = OodlesBlogEntry.findAllByTagAndPublishAndLocked(params.tag.trim(), true, false [max:5, offset:params.offset, sort:"dateCreated", order:"desc"])

But this statement is not working. please help me to solve this issue.

Error when i put both in one line.

| Error 2014-10-06 12:40:52,133 [http-bio-8080-exec-5] ERROR errors.GrailsExceptionResolver  - InvalidPropertyException occurred when processing request: [GET] /blog/tagged/android
No property found for name [tag] for class [class com.oodles.blog.OodlesBlogEntry]. Stacktrace follows:
Message: No property found for name [tag] for class [class com.oodles.blog.OodlesBlogEntry]
    Line | Method
->>  104 | methodMissing in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|    569 | byTag         in com.oodles.blog.BlogController$$EOrtPHk8
|    198 | doFilter . .  in grails.plugin.cache.web.filter.PageFragmentCachingFilter
|     63 | doFilter      in grails.plugin.cache.web.filter.AbstractFilter
|     53 | doFilter . .  in grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter
|     49 | doFilter      in grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter
|     82 | doFilter . .  in grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter
|    270 | doFilter      in com.planetj.servlet.filter.compression.CompressingFilter
|   1145 | runWorker . . in java.util.concurrent.ThreadPoolExecutor
|    615 | run           in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run . . . . . in java.lang.Thread

Solution

  • The reason for the error is that findAllByTag is not a GORM dynamic finder. It's a method that is added by the taggable plugin to any domain classes that implement the Taggable interface.

    Because findAllByTag is not a dynamic finder, you cannot combine it with other dynamic finders, e.g. findAllByTagAndPublish.

    When you install the taggable plugin, 2 additional classes are added to your domain, Tag and TagLink. The latter joins a tag with a domain object that has been tagged with it, e.g.

    mysql> select * from tag_links limit 5;
    +----+---------+--------+---------+-----------+
    | id | version | tag_id | tag_ref | type      |
    +----+---------+--------+---------+-----------+
    |  1 |       0 |      1 |       1 | blogEntry |
    |  2 |       0 |      2 |       1 | blogEntry |
    |  3 |       0 |      3 |       1 | blogEntry |
    |  4 |       0 |      4 |       2 | blogEntry |
    |  5 |       0 |      5 |       2 | blogEntry |
    +----+---------+--------+---------+-----------+
    

    You could certainly write an SQL query that would retrieve all the published, unlocked blog entries with a particular tag, but it wouldn't be pretty. You might even be able to use HQL, but personally I wouldn't bother. I understand that your current approach requires you to run 2 queries where only 1 should be necessary, but does this really matter? Unless you have hundreds/thousands of blog posts (which seems unlikely) it's not going to make much practical difference.

    Update

    Alternatively, you could get all blog entries with a particular tag via:

    def entries =  OodlesBlogEntry.findAllByTag(params.tag)
    

    Then you can do filtering out unpublished or locked tags, sorting, and pagination in Groovy code:

    def filteredEntries = entries.findAll{ it.published && !it.locked }
    def sortedEntries = filteredEntries.sort { it.title }
    
    def max = 5 
    def offset = params.offset
    
    // TODO check the size of sortedEntries and adjust the pagination params to prevent an 
    // IndexOutOfBoundsException
    def entriesPage = filteredEntries.sort[offset..<offset + max]