9

I'm still learning Grails and seem to have hit a stumbling block.

Here are the 2 domain classes:

class Photo {
    byte[] file 

    static belongsTo = Profile
}


class Profile {
    String fullName
    Set photos

    static hasMany = [photos:Photo]     
}

The relevant controller snippet:

class PhotoController {

    def viewImage = {

      def photo = Photo.get( params.id )
      byte[] image = photo.file 
      response.outputStream << image

    } 
} 

Finally the GSP snippet:

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:'profileInstance.photos.get(1).id')}" />

Now how do I access the photo so that it will be shown on the GSP? I'm pretty sure that profileInstance.photos.get(1).id is not correct.

Opal
  • 81,889
  • 28
  • 189
  • 210
Kevin
  • 956
  • 3
  • 11
  • 24
  • Did you try this? It should cause 'viewImage' to get called with id=1, referring to a Photo instance assuming there is a 'profileInstance' in scope. You may need to adjust the response content type Are you asking how to select _which_ photo is displayed? – Ken Gentle Nov 03 '08 at 18:37
  • I'm hoping to display the first photo in the set, thanks. – Kevin Nov 04 '08 at 01:22

6 Answers6

4

If you have a url for the image, you just have to make sure you return the appropriate anser in the controller:

  def viewImage= {
    //retrieve photo code here
    response.setHeader("Content-disposition", "attachment; filename=${photo.name}")
    response.contentType = photo.fileType //'image/jpeg' will do too
    response.outputStream << photo.file //'myphoto.jpg' will do too
    response.outputStream.flush()
    return;
  }
Miguel Ping
  • 18,082
  • 23
  • 88
  • 136
3

As it is a Set, if you want the first element, you will have to go:

profileInstance.photos.toArray()[0].id

or

profileInstance.photos.iterator().next()
Hates_
  • 66,613
  • 6
  • 32
  • 37
  • Yes, the /photo/viewImage/{anyPhotoId} does show a photo correctly. Actually I think I used a Set instead of ArrayList. Is this the cuase of the problem? Thanks! – Kevin Nov 04 '08 at 01:21
  • @Walter - Ah yes. I have amended my answer. – Hates_ Nov 04 '08 at 11:01
2

now, i actually think storing the photo as a binary blob in the database isnt the best solution - though you might have reasons why it needs to be done that way.

how about storing the name of the photo (and/or the path) instead? If name clashing issues are probable, use the md5 checksum of the photo as the name. Then the photo becomes a static resource, a simple file, instead of a more complicated and slower MVC request.

Chii
  • 14,540
  • 3
  • 37
  • 44
  • This could be an option. I 'll need to explore it further. Thanks! – Kevin Nov 10 '08 at 04:58
  • 1
    What about securing that image? If you're using a direct URL to the file, you lose the ability to (or make it much more difficult to) secure the image to specific users/roles. – billjamesdev Nov 10 '08 at 19:48
  • @bill: i guess it depends on the requirements. Security will come at a cost, and my method is a bit harder to secure (not impossible, but its probably simpler using other's suggestions if security is important). – Chii Nov 18 '08 at 07:32
  • 1
    Besides security, one can mention that then you become prone to "file system issues" (say hosted in an environment where someone can delete your files). Plus, if you store a blob in the db, you can encapsulate that in a class that can store other metadata, which you can use to do all kind of interesting things like "find me all pictures of a cat" that are hard to do with file system storage. While performance is important, there are all sorts of reasons why storing a file in a relational environment can make sense. – Visionary Software Solutions May 15 '11 at 06:10
  • Storing stuff on the file system also complicates backup/restore, exports, etc. and adds additional infrastructure complexity and configuration. Also if you are using a dynamic CDN like Akamai the additional overhead of loading the images from the DB is not going to be an issue for cached requests. I've built a CMS using images loaded from the DB and the performance hit is not really noticeable. – Ken Liu Oct 29 '12 at 01:53
1

I´m learning grails too was searching for an example like this one. The GSP snipplet didn´t work for me. I resolved by replacing the single quotes around profileInstance.photos.get(1).id

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:'profileInstance.photos.get(1).id')}" />

with double quotes:

<img class="Photo" src="${createLink(controller:'photo', action:'viewImage', id:"profileInstance.photos.get(1).id")}" />

Now grails resolves the expression around the double quotes. Otherwise it takes it as string.

stitakis
  • 891
  • 1
  • 7
  • 7
0

id:'profileInstance.photos.get(1).id' should be id:profileInstance.photos.get(1).id. no quota

0

My guess is you need to set the content type of the response stream. Something like:

response.ContentType = "image/jpeg"

This may or may not need to be before you stream to the response stream (can't imagine that it would matter). I'd just put it before the outputStream line in your code above.

billjamesdev
  • 14,554
  • 6
  • 53
  • 76