I want to upload an image using a groovy on grails.
My gsp page is as follows (I am showing a simplified version of the original)
<g:form controller="post" action="save" enctype="multipart/form-data">
My picture <input type="file" name="myPicture" />
<g:submitButton name="submit" value="Save"/>
</g:form>
My domain class is as follows:
class Post {
byte[] myPicture
static mapping = {
myPicture type: "blob"
}
I need this mapping otherwise MySql will create a smallblob which is to small to fit the images
static constraints = {
myPicture(nullable:false)
}
}
At the controller I have an action called save which is as follows:
def save = {
def post = loadPost(params.id)
post.properties = params
if(post.save()) {
print "hallo world"
redirect(action:'list', params:params)
} else {
render(view:'edit', model:[post:post])
}
}
The exception is thrown when I try to save the image at the DB.
2009-04-27 18:16:07,319 [20806951#qtp0-0] ERROR errors.GrailsExceptionResolver - java.lang.ClassCastException: [B cannot be cast to java.sql.Blob
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.ClassCastException: [B cannot be cast to java.sql.Blob
Any hint why is this?
BTW, I've seen in a tutorial that images were handled as strings but it didn't work
as well.
I found a similar question on Nabble:
http://www.nabble.com/MySQL-and-Blobs-td16116885.html
Two possible solutions are suggested:
Change the constraints of the blob property to a large max-size, to stop it from using "TinyBlob".
Use the Hibernate Blob implementation instead of byte[] for the property's type declaration. This will require you stream data into the Blob, instead of direct assignment, but the post above gives code to do so.
Can you try using Spring's MultipartFile within your loadPost() method?
Here's an example from the docs:
def upload = {
def f = request.getFile('myFile')
if(!f.empty) {
f.transferTo( new File('/some/local/dir/myfile.txt') )
response.sendError(200,'Done');
}
else {
flash.message = 'file cannot be empty'
render(view:'uploadForm')
}
}
I believe you can access f.bytes directly.
try this way:
def save = {
def post = loadPost(params.id)
def f = request.getFile('myPicture')
post.myPicture = f.getBytes()
post.pictureType = f.getContentType()
if(post.save()) {
Related
I'm currently developing a grails application (Version 3.1.2) and I got a frustrating error that I currently cannot solve.
Lets have an example case:
// Domain classes
class RootBean {
NestedBean nestedBean
}
class NestedBean {
int nestedInteger
}
not much to say about it, its just an 1 to 1 relation with no back reference
Now lets specify my problem: I've got a create and an edit view which both render a editTemplate with all the possible inputs. With a new Object (create) everythings works fine but with a existing Object I want to update I get this GSP Error Message:
URI
/VMPMessung/edit/2
Class
groovy.lang.MissingPropertyException
Message
Request processing failed; nested exception is org.grails.gsp.GroovyPagesException: Error processing GroovyPageView: [views/rootBean/edit.gsp:13] Error executing tag <g:render>: [views/rootBean/_editTemplate.gsp:1] Error executing tag <g:form>: [views/rootBean/_editTemplate.gsp:150] Error executing tag <f:widget>: No such property: nestedInteger for class: RootBean
Caused by
No such property: nestedInteger for class: RootBean
The GSP Code:
<f:widget class="form-control"
property="nestedBean.nestedInteger"
bean="RootBean"/>
I also debugged through the Taglibary and discoverd that it's going wrong cause of the Type Integer, I got other String fields in the real object and they are working fine. The Error is thrown in the FormFieldsTagLib class at line 569
private CharSequence renderNumericInput(BeanPropertyAccessor propertyAccessor,Map model, Map attrs) {
if (!attrs.type && model.constraints?.inList) {
attrs.from = model.constraints.inList
if (!model.required) attrs.noSelection = ["": ""]
return g.select(attrs)
} else if (model.constraints?.range) {
attrs.type = attrs.type ?: "range"
attrs.min = model.constraints.range.from
attrs.max = model.constraints.range.to
} else {
attrs.type = attrs.type ?: getDefaultNumberType(model )
if (model.constraints?.scale != null) attrs.step = "0.${'0' * (model.constraints.scale - 1)}1"
if (model.constraints?.min != null) attrs.min = model.constraints.min
if (model.constraints?.max != null) attrs.max = model.constraints.max
}
if(propertyAccessor != null && attrs.value) {
attrs.value = g.fieldValue(bean: propertyAccessor.rootBean, field: propertyAccessor.propertyName)
// This call causes the Error
// Debugging Values: propertyAccessor.rootBean: RootBean,
// propertyAccessor.propertyName: nestedInteger
}
return g.field(attrs)
}
I guess they are trying to find the fieldName on the RootBean instead of the NestedBean but am I doing something wrong or is it a Bug on Grails side?
Hopefully some of you knows an answer to this, its really much a blocker for me :(
I am having the same issue, the weird thing is that in I am not having problem, I have it only in
I could fix it with a workaround, implementing in RootBean class a getter for nestedInteger:
def int getNumber() {
return nestedBean?.nestedInteger
}
That worked for me.
Could you solve it properly?
I am trying to display an image stored in my model using the following:
<img src="${createLink(controller:'attachments', action:'showImage', id: attachmentInstance.id)}" />
Here is the showImage method in controller attachments:
def showImage= {
println "In showImage"
def attachmentInstance = Attachment.get(params.id)
byte[] b = attachmentInstance.image
response.setContentLength(b.length)
response.getOutputStream().write(b)
}
Here is my domain class:
class Attachment {
byte[] image
String imageType
int imageSize
String attachmentType
String fileName
static mapping = {
image(sqlType: "blob")
columns {
'*'(nullable: true)
}
}
}
The action is not being executed, I have a prinlin to varify that.
The image is in the file and this code has been used in previous version of Grails.
Am I doing something wrong or is there a bug?
Old versions of Grails controllers used closures and not methods. Newer versions uses actual methods on the controllers and not closures. So your method should be:
def showImage() {
...
}
and not
def showImage = {
...
}
How do I return values from a taglib that has been called in a controller action such that it automatically retains the full type structure of the values setup in the taglib?
I can use the out << approach but this returns strings or array of strings.
I have tried to use a [] mapping as used transfer a set of values at the end of an action to its view.
I have also tried a return statement again unsuccessfully - besides I need to return more than one set of values.
-mike
from the top of the documentation http://grails.org/doc/latest/guide/theWebLayer.html#tagReturnValue
class ObjectReturningTagLib {
static returnObjectForTags = ['content']
def content = { attrs, body ->
someValue()
}
}
I think this could solve your problem
package com.campaign
import java.util.*;
class UserDetailsTagLib {
def springSecurityService
static namespace = "jft"
#here we are defining that this getPrincipal and getArrayListAsObj tag used to return object
static returnObjectForTags = ['getPrincipal','getArrayListAsObj']
#this tag will return obj
def getPrincipal = {
return springSecurityService.principal
}
# this tag is used to return the array list of string
def getArrayListAsObj = { attrs , body ->
ArrayList arrayList = new ArrayList();
arrayList.add("C");
arrayList.add("A");
arrayList.add("E");
arrayList.add("B");
arrayList.add("D");
arrayList.add("F");
return arrayList
}
}
I understand your problem. If you want to have the Intellisense on the var you got from a taglib, the only thing you can have is this (it's a little redundant)
In a gsp for example, if you have a TagLib with namespace myTaglib:
First call the action of your taglib to set the value of a var:
<myTaglib:person var="currentUserFromTaglib" />
Where the person tag in the myTaglib is just for this purpose:
def person = { attrs ->
this.pageScope."$attrs.var" = new Person(name:'Giuseppe', surname:'Iacobucci')
}
After this, you need to write:
<g:set var="currentUser" value="${currentUserFromTaglib as Person}"/>
And include in you gsp:
<%# page import="your.package.Person" %>
After that, in the gsp currentUser is recognized as type Person.
In a controller, you simply call the myTaglib and cast the result like so:
def myvar = myTaglib.person() as Person
Obviously if you need more a complex object as I read from your comments, then create a plain UI object with all information you need inside and do the same trick.
I am trying to implement a "bulk" insert for hasMany. And got it 90% there, but hit a hiccup with my polyclass design. I have a model like
class Parent {
static hasMany = [references: Reference]
}
class Reference {
static belongsTo = [parent: Parent]
String name
}
class ConcreteReference extends Reference{
String childName
}
I was able to get the create working(defined by creating records) by having markup like
<form action='reference/1/edit>
<input name='references[0].name' value='name1' />
<input name='references[0].childName' value='childName1' />
<input name='references[1].name' value='name2' />
<input name='references[1].childName' value='childName2' />
</form>
But the issue is it always creates the concrete type(class='domain.Reference'), so "child name is always null.
I used:
def edit(def id){
def parent = Parent.get(id)
//i actually clear all the old references first (didn't show that code)
parent.properties = params
parent.save(flush:true)
}
How can I either specify the "concrete type"( I tried a hidden value of class it didn't work) or is there an easy way to loop through params.reference[idx] create it and then add it to Parent?
hopefully that is clear, let me know if you need any clarification.
My manual way of parsing params(not I hard code ConcreteReferences, but i was able to group the params):
def refRegex = /^([a-zA-Z]+\[\d+\])/
for (ref in params.groupBy { it -> it.key.find(refRegex)}.findAll{it.key}){
//this will be like references[0]: [references[0].name : 'test', etc]
//for each one create a FreeFormReference
def _ref = new ConcreteReference(ref.value.collectEntries{it -> [it.key.replace(ref.key + '.', ''), it.value]})
log.info('created reference ${_ref}')
parent.addToReferences(_ref)
}
How do I write options so I can generate it into an HTML select? The problem with this is "options" needs a set, not an array
Here is everything I have. I know the naming convention is bad, and I will fix that, but for right now I've been on this issue for days now.
Controller Class
import org.springframework.dao.DataIntegrityViolationException
import grails.plugin.mail.*
class EmailServiceController {
static defaultAction = "contactService"
def contactService() {
def options = new ArrayList()
options.push("Qestions about service")
options.push("Feedback on performed service")
options.push("Other")
options.push("Why am I doing this")
options
}
def send() {
sendMail(){
to "mygroovytest#gmail.com"
from params.email
subject params.subject
body params.information
}
}
}
Domain class
class EmailService {
static constraints = {
}
}
g:select call from the gsp
<g:select name = "subject" from = "${options}" noSelection="Topic"/>
also tried the following with "${selectOptions}" instead of "${options}" with no luck
def selectOptions() {
def options = new ArrayList()
options.push("Qestions about service": "QAS")
options.push("Feedback on performed service":"FoPS")
options.push("Other":"Other")
options.push("Why am I doing this":"WHY")
return options
}
Ok, I think I might know what is going on here. The missing piece to the question is what gsp is being called. Here is the appropriate way:
class EmailServiceController {
def contactService() {
def options = ["Qestions about service", "Feedback on performed service", "Other"]
// assumes you are going to render contactService.gsp
// you have to push the options to the view in the request
[options:options]
}
}
And then in contactService.gsp you would have:
<g:select name="subject" from="${options}" noSelection="['Topic': 'Topic']"/>
Your options is neither an array nor map. There is a syntax error. That's why you have only one option in your select. You need to enter either a real list or a map, like that:
def selectOptions() {
def options = [:]
options["Qestions about service"] = "QAS"
options["Feedback on performed service"] = "FoPS"
[options:options]
}
Using a map you can use it in the view like this:
<g:select name="subject" from="${options.entrySet()}"
optionValue="key" optionKey="value"
noSelection="['Topic': 'Topic']"/>
You need to use double quotes in your tags, not single quotes. With single quotes, you're just passing a String that looks like '${options}' instead of passing a GString with the value of options.
<g:select name="subject" from="${options}" noSelection="Topic"/>
In addition, assuming you're calling the contactService action, you need to return options instead of returning options.push("Other"). push() returns a boolean, which means the implicit return of contactService is the boolean result of push() instead of options.