I'm having the strangest problem with a controller in a Grails project. I am trying to do a simple update of a domain object. Here is a simplified version of the controller
def updateRecord = {
def foundHVT = Process.get(params.hvt)
foundHVT.summaryBy = params.summaryBy
foundHVT.catalogBy = params.catalogBy
foundHVT.editBy = params.editBy
foundHVT.produceBy = params.produceBy
foundHVT.correctedBy = params.correctedBy
// a bunch more of these
foundHVT.save(flush: true);
redirect (action:resource, id: params.hvt)
}
If I run the a new instance of the application of and use this controller to update an object, it doesn't work, the object doesn't save. It will look fine within the controller. I can, for example, re-query the object and the changes are there, post save.
Now here's where it gets weird. If i use the preset scaffold edit controller and update/save an domain object -- and then switch back to this "updateRecord" controller it works FINE until i shut down the server it is working on?!?
I realize I am missing something very basic, but I can't find what it is. Any guidance would be most graciously appreciated.
DM
As HVGOTCODES noted Grails Clean seems to have fixed whatever weirdness was going on with this controller.
try putting a "def scaffold=true" in your controller if it does not already have the normal entry points.
Probably scaffolding save fills some field that you don't.
Possible problems:
Do check save() result and render foundHVT.errors the way Grails does. Add failOnError: true parameter to save() or just check foundHVT.hasErrors(). Look at foundHVT.errors.allErrors for validation problems.
Why not foundHVT.properties = params?
What is there is no foundHVT?
Related
I came across a post from Donal which I think was asking he same thing but did not really anwer the question, a little puzzled and wonder if possible.
If I have a tag lib, user provides controller action I Wish for it to then go off query controller and return result as a list, I tried g.include with no luck. I have tried to expand on this below but don't know too much about it and if at all possible to actually get a value back from the given primaryAction or def value within controller
if (attrs.primaryController && attrs.primaryAction ) {
//def nlist= g.include(controller:'${attrs.primaryController}', action:'${attrs.primaryAction}', id:'${attrs?.primaryId}')
def controllerArtefact = grailsApplication?.getArtefactByLogicalPropertyName("Controller", "${attrs.primaryController}")
def controllerClass = controllerArtefact?.getClazz()
def aaa=controllerClass.declaredFields.each {
it.name=="${attrs.primaryAction}" }
println "-->"+aaa.getMetaPropertyValues().
println "-------------????? ${aaa}"
}
I also thought maybe another way would be for the controller that loads up the gsp which contains the taglib should easily be able to pass a list as a variable down to the taglib, the taglib then takes attrs.newList and represents it as List.
Doing things this way the plugin was complaining about no id, really bizzare since the typical list produced from within plugin looked identical.
I have created several controllers in my Grails project and put data for each controller in the bootstrap, but the data does not appear in the table for each controller that scaffold provides as the default view. I have checked inside dbconsole to be certain that the data is there, which it is. I have also refreshed the dependencies to make certain that the version of the scaffolding plugin is not corrupted. I am using Grails 2.3.5 and Scaffolding 2.0.1.Are there any suggestions of what could be wrong?
class DepartmentController {
static scaffold=Department
def index() { }
}
Looking back at other examples of using scaffolding I realize now that I should have taken out the index portion of the code, even though it is empty.
Remove your the index method and make it like this:
class DepartmentController {
static scaffold=Department
}
Put some log messages into the controllers (or debug the app) right after the controller loads the data using the domain class in order to see if the query has resulted in any domain instances.
If not, activate sql logging and check the exact select statement executed. Possibly you have something wrong in your domain mapping so a wrong select stmt is sent to the db
I am following this tutorial http://guides.rubyonrails.org/v3.2.13/getting_started.html to build my rails app in version 3.2.13 . If you go to the section 6.9 you will find controller and view for creating new posts . Here I do not get how #post variable is passed from new action to create action and where is create function called ? Also , I faced the same problem while working on edit and update actions . Please guide me through this .
It's not passed to create action, it's instantiated again with params you pass from the form displayed with new action.
create action is called with POST request to the path specified in config/routes.rb, leading to specific controller and action.
#post is not passed from new to create the params hash is passed into the create method #post is then set using the new method of the model not the controller. create calls new and then save and returns the object. new returns the object without saving and then save returns the validity of the object. That is why the create method in the controller calls new and then has a conditional statement for save. It is basically saying initialize this object then if it is a valid object do one thing if it is not do another. The create action is not called because of this check.
#this will return true if valid or false if invalid
Post.new(params[:post]).save
#this will always return the Post object which conditionally is true in Ruby
Post.create(params[:post])
#To use the create in a conditional statement it would be
Post.create(params[:post]).valid? || Post.create(param[:post]).save
The last line is unnecessarily redundant and thus why the example uses new followed by save.
create method for a Model is more succinct but probably best to use when you know the object is valid.
Hope this gives you a better understanding but if you are still confused please let me know and I will try to explain further.
I'm working with the domain class Alojamiento, and its generated controller and views. The next code works:
I have included in the form of a view another form:
<g:render template="../caracteristicas/form" bean="${params.caracteristicasInstance}" />
Now, the edit action of the controller has:
def alojamientoInstance = Alojamiento.get(id)
def caracteristicasInstance = alojamientoInstance.caracteristicas
[caracteristicasInstance: caracteristicasInstance,
And to the update action of the controller:
def caracteristicasInstance = Caracteristicas.get(id)
caracteristicasInstance.properties = params
caracteristicasInstance.save(flush: true)
As I said, the above code works, but it is not protected against errors, so I'm trying to use the update action of CaracteristicasController (I'm following this approach: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html). The next code does NOT work, but I think it explain itself what I'm trying:
CaracteristicasController caracteristicasController = new CaracteristicasController()
CaracteristicasController.properties = params
CaracteristicasController.params.doNotRedirect = 'true' // See: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html
CaracteristicasController.update()
By the way, the error of Grails is: "Cannot set read-only property: properties"
UPDATE 1
I think I didn't explain something well. I have in _form.gsp 3 embedded _form.gsp (I said in my question 1 to simplify). So when I edit _form.gsp, the others must be updated too. I want to call the update action of the "child" controllers to update the forms, but not move to them. I want to keep being in the "parent" controller so when everything updates, the show.gsp of the "parent" will appear. Do I explain it better now?
Why don't you redirect or chain with all need params?
I'm using Grails 1.2.1. I have this method in my controller …
class SocialMediaCacheProxyController {
def index = {
def url = params.url
if (params.dumpAll != null) {
transportCacheService.processCacheDump(request.getRemoteAddr(), response)
} else if (url != null) {
doCacheTransport(request, response)
} // if
}
Problem is, both execution paths write content to the response. However, I think Grails is trying to render a page at the end of the index method, because I repeatedly get the below error after invoking this method …
1339754 [http-8080-4] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/socialmediaproxy].[default] - Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: response.getWriter() called after response.getOutputStream()
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer.getWriter(GrailsPageResponseWrapper.java:284)
at org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper$3.activateDestination(GrailsPageResponseWrapper.java:125)
Any ideas how I can get Grails to stop rendering anything after my method is complete? Thanks, - Dave
If you don't tell Grails what to render, it will render based on convention. In your case, it is looking for an index.gsp. Controllers must return something. That's the whole point. So you can either use the convention and create an index.gsp that gets returned, or you can manually implement the render() method.
http://grails.org/doc/latest/ref/Controllers/render.html
It looks like most of the controller code that works with the ModelAndView keeps an eye on whether or not the ServletResponse has been committed.
I would posit that you could call response.flushBuffer() at the end of your controller action. This will cause the response to be marked as committed, and the controller will not return a ModelAndView.
An alternative would be to call response.outputStream.flush(), which would also result in the response being committed. This is what I usually end up doing after manually working with the response (e.g. for file downloads).
Note: I'm not sure where this falls within the realm of "best practices" - usually you're supposed to rely on the container to handle the flushing of the servlet streams. It's possible that there will be inadvertent side-effects by doing this. You'll probably have to test it out and see what happens with your app and the container you run it in.
I think you're trying to do something counter to the design of an MVC application. Controllers exist to send you somewhere based on parameters. Maybe you could look at using a Service instead, through an AJAX call. Or, if your controller action is changing data that you want to show, you could just redirect back to the page that the call came from. Start here:
http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html
http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html
I think Grails maybe forwarding to index.gsp, because it does so by default when you don't return a value.
Therefore, i think you should return null at the end of the index-closure to signal grails that you have already written everything you wanted to the output stream.
try this
render (view: "/the name of the page", model: [text:'hi there')
NB
if u want to render a template instead of "view" you put "template"