Grails File Upload Problems - spring

I'm trying to emulate the file upload code from the grails website, and I'm running into some problems. I'm using the same code as found here. Here is my code:
<g:form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myFile" />
<input type="submit" value="Upload" />
</g:form>
and
def upload = {
def f = request.getFile('myFile')
if(!f.empty) {
flash.message = 'success'
}
else {
flash.message = 'file cannot be empty'
}
}
I'm receiving the following error at runtime:
Message: No signature of method: org.mortbay.jetty.Request.getFile() is applicable for argument types: (java.lang.String) values: {"myFile"}
Caused by: groovy.lang.MissingMethodException: No signature of method: org.mortbay.jetty.Request.getFile() is applicable for argument types: (java.lang.String) values: {"myFile"}
It appears to be related to some Spring configuration. Spring does not appear to be injecting MultipartHttpServletRequest, so my request doesn't have the appropriate method. I just created this applications using grails create-app. I have not modified the resources.groovy file. I'm using grails 1.0.3.
Any help is much appreciated. The grails website makes this look so easy.

Problem solved!
I was using the example code for uploading files to Grails differently than the original author probably intended. The problem is that when the upload method of the controller was called, it was sometimes for the original render of the Upload page. The request in that method was was not of type MultipartHttpServletRequest. When I did a POST with my file to upload, then Spring did the correct thing and changed my requestion to MultipartHttpServletRequest. So, I needed to do a simple check in my update controller method before using my request like a MultipartHttpServletRequest.
if(request instanceof MultipartHttpServletRequest)
{
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("myFile");
if(!f.empty)
flash.message = 'success'
else
flash.message = 'file cannot be empty'
}
else
flash.message = 'request is not of type MultipartHttpServletRequest'

Now with the Grails 2.x use:
<g:uploadForm name="upload" action="upload" method="POST">
<input type="file" name="file" />
</g:uploadForm>
def upload = {
def file = request.getFile('file')
assert file instanceof CommonsMultipartFile
if(!file.empty){ //do something }
else { //do something }
}
More clean, more simple.

make sure you update the html (your gsp with the form to upload from) to have the enctype as they show:
<g:form action="upload" method="post" enctype="multipart/form-data">
Hope that is helpful, seems too obvious but it's my first thought after seeing your error message.

Someone here seems to be having the same troubles you had. He says he "fixed" it:
Solved. It was my mistake, I was going in action save before submitting the form, so I suppose there was no file.
Not sure how to take what he said, but maybe it'll help you.

Related

Aurelia validatejs not working when bind on a object

I was playing around with aurelia-validatejs and was able to validate simple fields on a page. On the same page, I tried initializing a object and bind validation to that object and it stops working:
user_data:IUserData = {
Login:"",
Id : null,
UserProfile: {
UserId: null
},
Permissions: null
};
constructor(){
this.reporter = ValidationEngine.getValidationReporter(this.user_data);
// if I just use this and not user_data object,
// it works and error message is displayed in UI
this.validator = new Validator(this.user_data)
// when I use this.user_data (user_data object), it does validate
// and I can see validation result on console, but it's not shown in UI
.ensure('Login').required().length({minimum: 3, maximum:10});
this.observer = this.reporter.subscribe(result => {
console.info(result);
});
}
Someone mentioned that validatejs looks for a label, and I do have it, it worked when I initialize on this object but as soon as I want to validate on this.user_data property, it just doesn't display in UI, but I can see it on console.
<form action="" submit.delegate="createUser()">
<div class="input-group ${user_data.Login | loginClass}">
<label></label>
<input placeholder="Login" type="text" class="form-control"
keyup.delegate="validate()" value.bind="user_data.Login & validate">
</div>
</form>
this doesn't work, but if I clear user_data like:
user_data:IUserData = {
Login:"",
Id : null,
UserProfile: {
UserId: null
},
Permissions: null
};
constructor(){
this.reporter = ValidationEngine.getValidationReporter(this);
//if I just use this and not user_data object,
//it works and error message is displayed in UI
this.validator = new Validator(this)
.ensure('Login').required().length({minimum: 3, maximum:10});
this.observer = this.reporter.subscribe(result => {
console.info(result);
});
}
and
<form action="" submit.delegate="createUser()">
<div class="input-group ${user_data.Login | loginClass}">
<label></label>
<input placeholder="Login" type="text" class="form-control"
keyup.delegate="validate()" value.bind="Login & validate">
</div>
</form>
This works and is displayed in UI. I searched a little bit on stackoverflow and got few results similar (My problem is similar. I have error messages on UI if I don't use it on a object but when I try to use it on an object, it logs on console but it doesn't display in UI)
I also found this but it wasn't of much help.
I found one more which wasn't of much help either.
I understand there are a lot of articles which might make this question marked duplicate, the reason I'm asking is aurelia is quite new technology and stuffs are changing quite frequently.
Thanks in advanced!
So I dug around a little bit and asked developers in Gitter. As it turns out, it's a bug in validatejs plugin.
Recent changes were made to make something available on all classes, and when that change was done, validatejs looks for validationError Reporter on same model even if we provide different model.
A small hacky workaround is to have
this.__validationReporter__ = ValidationEngine
.getValidationReporter(this.user_data);
Instead of:
this.reporter = ValidationEngine.getValidationReporter(this.user_data);
I have reported this issue and will update once they come up with something.
For now I'm gonna use
this.__validationReporter__ = ValidationEngine
.getValidationReporter(this.user_data);
Or one other workaround is to downgrade to 0.3.x which is not very recommended as there might have been some important changes.
Have you used form-group? Usually our validation problems come down to HTML structure not conforming to the library.
<form action="" submit.delegate="createUser()">
<div class="form-group ${user_data.Login | loginClass}">
<label></label>
<input placeholder="Login" type="text" class="form-control"
keyup.delegate="validate()" value.bind="Login & validate">
</div>
</form>

Spring mvc: I cant map form action url to controller action

I apologize in advance if this or a similar question has already been asked, but I could not find a suitable answer.
I have a simple form like this in EditUser.jsp (mapped to: .../admin/users/edit/{userId}):
<form action="/admin/users/edit/addRole/${user.userId}" method="POST">
<select name="role">
<c:forEach var="role" items="${roles}">
<option value="${role}">${role}</option>
</c:forEach>
</select>
<button type="submit" value="AddRole">Add Role</button>
</form>
And #RequestMapping like this:
#RequestMapping(value = "/admin/users/edit/addRole/${userId}", method = RequestMethod.POST)
public String addUserRole(
Model model,
#RequestParam("role") String role,
#PathVariable(value="userId") long userId)
{
...
return "redirect:/admin/users/edit/${userId}";
}
The problem is the result of the request: HTTP Status 404 - /admin/users/edit/addRole/7- "The requested resource is not available" (7 is some user id). A cannot map the POST request to the controller action. I already tried with th:action but it redirects me to the previous page .../admin/users.
Any help pointers appreciated .
I think you url is wrong. As long as you do not deploy the application in the servlets container root path, it will not work because the url is missing the applications name. So a correct url would be something like:
<form action="myAppName/admin/users/edit/addRole/${user.userId}" method="POST">
But better would been using <c:url> or <spring:url>-tag this adds the application name to the url (if the given url starts with an /)
<form action="<c:url value="/admin/users/edit/addRole/${user.userId}" />" method="POST">
for some more information have a look at this two answers:
How to use relative paths without including the context root name? (the highes ranked answer of BalusC is for an quite old jsp version (<2.0)) so take the answer with the c:url tag
How to use with an tag?
I finally found the error - $ sign in #RequestMapping annotation. A just removŠµ $ from annotation and from return "...url" and that's all.

File Uploading MVC3 and Microsoft Web Helpers

I am currently using the file upload helper that comes with Microsoft.WebHelpers like this
#FileUpload.GetHtml(initialNumberOfFiles: 1, allowMoreFilesToBeAdded: true, includeFormTag: false, uploadText: "Upload")
This correctly gives me a upload box but I am having two problems with this that I cannot seem to find an answer for.
The first problem is the box does not display the filename correctly if I have a long path.
The second problem is that I can add a bunch of new files but there does not seem to be a remove option that can be turned on.
I need to find a good tool to facilitate file uploads that will give me these options and seamlessly integrate with asp.net mvc3 or figure out a way to do this with the upload tool.
I am not sure what current tools are as far as nuGet packages go. However, I know that you can roll your own pretty easily.
In view:
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
<input type="file" id="files" name="files" size="60" /><input type="button">
...
<input type="submit">
}
<script>function(){ //make button add another input field with id="files"}
</script>
Note: new { enctype = "multipart/form-data" } is required to send files to the controller from a form.
In Action:
[HttpPost]
public ActionResult ActionName(IEnumerable<HttpPostedFileBase> files)
{
foreach(HttpPostedFileBase uploadFile in files)
{
//work with uploadFile
}
}

Grails WebFlow with Ajax

I am trying to transition to next state of a WebFlow using Ajax requests. But it stays in the same state and returns the GSP as response for that state while I am expecting the GSP for the next state.
Following is the WebFlow code:
def gettingStartedAjaxFlow = {
flow1 {
on("next") {
println "flow1"
}.to("flow2")
on("skip").to("flow2")
}
flow2 {
on("next") {
println "flow2"
}.to("flow3")
on("skip").to("flow3")
}
flow3 {
on("next"){
println "flow3"
}.to("finish")
on("skip").to("finish")
finish {
redirect(action:"index")
}
}
}
Following is the Ajax call I am making for the state transition:
$.ajax({
type: "POST",
url: "/UN/user/gettingStartedAjax",
success: function(data) {
$("#wizardDiv").html(data);
}
});
The GSPs for each state (flow1, flow2, flow3) contains a a code fragment having remoteForm & required next and skip submit buttons to transition to next state and as a result update the "wizardDiv" div. Following is the GSP fragment for flow1 state:
<g:formRemote name="flow1Form" url="[controller:'user', action:'gettingStartedAjax']" update="wizardDiv">
<p>You are in flow 1</p>
<g:submitButton name="next" value="Next Flow" />
<g:submitButton name="skip" value="Skip Flow" />
</g:formRemote>
I'm stuck on the same problem, Nearly figured it out,
what you need to do, is send back the Grails webflow "_flowExecutionKey" that keeps
track of the current state,
I'm sure you've seen this, as its the only decent result Google finds.
I send an ajax request to an action, which populates a template and sends it back
with an input tag,
<input id="flowExecutionKey" name="_flowExecutionKey" value="${request.flowExecutionKey}" size="100"/>
But you could try send a temple back marked up like JSON with the "_flowExecutionKey" along with the data you want to send back,
That's my two cents
As well as keeping track of the execution (as Daxon posted), you'll need to make sure your buttons are named _eventId_next and _eventId_skip. g:submitbutton is normally clever enough to do this for you but it might not be inside of a remoteForm.
Also, my web flow code uses the parameter execution, not flowExecutionKey - which version of Grails are you using?
Here a solution that works in grails 2.5.3 at least for one single action. The id and name of the button are automatically modified to include "eventId" as prefix but this still did not work for me unless I added _event_id manually as input parameter. However, I'm not sure how this can work for multiple possible events.
<g:formRemote name="flow1Form" url="[controller:'user', action:'gettingStartedAjax']" update="wizardDiv">
<input type="hidden" id="execution" name="execution" value="${request.flowExecutionKey}"/>
<input type="hidden" id="_eventId" name="_eventId" value="next"/>
<fieldset class="form">
</fieldset>
<fieldset class="buttons">
<g:submitButton name="next" value="Next flow"/>
</fieldset>
</g:formRemote>

Grails Duplicate Error Messages

I'm new to grails and I have a problem:
I have this snippet of GSP:
<g:form url="[controller:'main',action:'login']">
<label for="name">Usuario:</label><br/>
<input type="text" name="name" /><br/>
<label for="pass">Password:</label><br/>
<input type="password" name="password"/><br/>
<input type="submit" value="Login"/><br/>
<g:renderErrors bean="${cmd}"/>
</g:form>
The Controller (MainController.groovy) uses a Command Object, here's the code for both:
def login = { LoginCommand cmd ->
if(cmd.validate()){
redirect(action:'ok')
}else{
render(view:'index',model:[cmd:cmd])
}
}
class LoginCommand {
String name
String password
static constraints = {
name(blank:false,size:5..10)
password(blank:false,size:5..10)
}
}
The problem is that when I enter a bad name or pass (blank or outside the range) it shows me 4 errors, two for the password and two for the username. They are the same, but duplicated.
I found that creating a method "bool validateCommand(){ name && password }" and replacing it for command.validate() does not throw duplicates, but I want to use the constraints features of Grails to keep things DRY.
Any idea why this happens? Thanks so much!
When you inject command objects into controller actions, Grails executes validate() automatically, so there is no need to call it manually. Try
if(!cmd.hasErrors())
instead of
if(cmd.validate())
It seems, that every call to validate() adds new (duplicate) errors to the command object. IMHO this shouldn't happen and probably is a bug in Grails. You should consider reporting this issue.

Resources