Search code examples
grailscontrollers

Grails controllers dynamic finders


I'm kinda new to Grails so I need help with this matter. Imagine I have these classes:

Class User{
String name
String nr

}

class Computer{

String processor
String ram
User user
}

Class Room{
String roomNr
Computer computer
}

I want to do a controller like this:

def print= {

        def user = User.get(1)

        def computer = Computer.findAllByUser(user) // all computers filtered by User

        [computer: computer]       
    }

The controller works good, but I want to be able to pass not only the computer instances, but also the Room's with that computer id's. I dont know how to do it, but would be something like this (same controller, same action):

def print= {

        def user = User.get(1)

        def computer = Computer.findAllByUser(user) // all computers filtered by User
        def room = Room.findAllByComputer(computer) ##

        [computer: computer]       
    }

Well, this is wrong because, where the ### is, 'computer' represents a list of id's and not a single id. As I am passing a list of computers to be printed in my gsp inside a g: each tag like this: (it. Processor, it. Ram). I dont know how to get all the rooms which are using the current computer in the each tag. This is a bit hard to explain, but basically my output would be:

<g:each in="${computer}"
Computer1:
Processor: ${it.processor}
Ram: ${it.ram}
Room: ????? (How to get here??)
</g:each>

Solution

  • I came up with something like this, but I didn't test it.

    Controller:

    def print = {
    
      def user = User.get(1)
      def computer = Computer.findAllByUser(user)
      def rooms = [:]
    
      // get rooms for that computer
      computer.each{
    
        def computerRooms = Room.findAllByComputer(it) // find all rooms where current computer is
        rooms.put(it.id, computerRooms) // map all the rooms with computer id
    
      }
    
      [computer: computer, rooms: rooms]      
    }
    

    View:

    <g:each in="${computer}">
      Computer1:
      Processor: ${it.processor}
      Ram: ${it.ram}
      Rooms: <g:join in="${rooms[it.id]}" delimiter=", "/>
    </g:each>
    

    Rooms map uses computer id as a key and list of all rooms where that computer is as value. Of course If I understood you correctly ;)

    EDIT

    If you need access room details, you can replace join tag with another each tag, like this:

    <g:each in="${computer}" >
      Computer1:
      Processor: ${it.processor}
      Ram: ${it.ram}
      Rooms: <br/>
      <g:each in="${rooms[it.id]}">
        Room id: ${it.id}
        Room number: ${it.number}
      </g:each>
    </g:each>
    

    And you can also implement the Room class toString() method, because join tag uses it to render text:

    Class Room{
      String roomNr
      ...
    
      String toString(){
        roomNr
      }
    }
    

    Now when you use join tag on list of Room class instances, it will print room number.