I am pretty new to grails and wondering how to use the respond object to the same view.
Note: I might not be clear with my question - but please check the below stuffs.
I have a one controller called "ProcessController.groovy" which have 2 methods inside them.
I have only one gsp called "create.gsp"
class PublishedSetController {
...
def create() {
Person p = new Person()
...
respond p // Working fine and this forward's to the view "create.gsp"
}
def createClone() {
Person p = new Person()
p.name = 'joe'
...
// Would like to forward to view "create.gsp"
respond view: 'create', model: p
}
}
Error:
Could not resolve view with name 'createClone' in servlet with name 'grailsDispatcherServlet'
I am aware that grails is mostly codeByConvention - but not sure how to fix this issue.
So can anyone please help, Thanks.
Correct syntax for respond is:
respond p, view: 'create'
You can read more about respond in the documentation.
Related
I'm using Grails 2.5.5, and I have a simple scenario here: A has many Bs.
And so I have a transactional service method which basically does the following:.
A a
if (isNew) {
a = new A()
} else {
a = A.findById(someId)
}
List<B> bList = getBsFromSomeOtherMethod()
bList.each { a.addToBs(it) }
a.save(failOnError: true)
The interesting thing is that if I create a new object (as in, isNew is true in the above logic), then I get the following exception when save() is called: reassociated object has dirty collection reference (or an array).
However, if I get an object which already exists in the DB, then everything works perfectly.
The workaround I found is that if I save the new object before adding Bs to A, then things work. But I would rather not have to call save() twice, and the code is just a lot cleaner if the call was just at the end.
I've googled the exception but nothing seems to explain what's going on here.
Can somebody help out with this?
Like others have said in the comments, you need to save the object so it exists in the database, and has an id. When you have a A has many Bs relationship, a new table in the database (something like a_b) is created to map A.id to B.id, which is why you can't add Bs to A without saving first.
A a
if (isNew) {
a = new A()
a.save()
} else {
a = A.findById(someId)
}
List<B> bList = getBsFromSomeOtherMethod()
bList.each { a.addToBs(it) }
a.save(failOnError: true)
Use findOrSaveBy for such an operations. You will get the proper object from db or persist new one:
def a = A.findOrSaveByField(field)
List<B> bList = getBsFromSomeOtherMethod()
bList.each { a.addToBs(it) }
a.save(failOnError: true)
Greeting everyone,
I am trying to pass a parameters from a URL to a findAll() method.
LINE3 I use findAll() to define mouse.
LINE2 def house will bring in the parameter DELAWARE when I go to the page: http://localhost:8080/TestApp/home/county/DELAWARE
House will only show one instance instead of a list.. is there anyway to pass the url instead of ["DELAWARE"]? (please see line 3) thanks :)
def county() {
def house = Home.findByCounty(params.id) //sends only user related address to view
def mouse = Home.findAll("from Home h where h.county= ?", ["DELAWARE"]);
if (!house) {
response.sendError(404)
} else {
[house:house, mouse:mouse ]
}
}
Working Code +1 #Danilo
def county() {
def house = Home.findAllByCounty (params.id) //sends only county specified thru URL e.g. http://localhost:8080/TestAPP/home/county/DELAWARE
if (!house) {
response.sendError(404)
} else {
[house:house ]
}
}
findBy* will return at most one row, if you want to get all rows use findAllBy*
In order to understand how the URL will be used by Grails you have to have a look at conf/UrlMappings.groovy. You may find something like this:
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
}
}
this means that when you call TestApp/home/county/DELAWARE what Grails is trying to do is use the home controller (HomeController), invoking the county method (def county(){...}) and passing DELAWARE as id.
This should work correctly if inside county method of the HomeController you have:
def filteredInstances = Home.findAllByCounty(params.id)
After saving a new instance of a domain class in grails, I have a "create another like this" button that brings up another create screen where the fields are populated with the values of the instance I just created.
In the first try, I passed all the existing field values as params in an alternate create button:
<g:link class="create" action="create"
params="[app:volInstance.app.id,
ass:volInstance.assessment.id,
name:volInstance.volName,
type:volInstance.volType.id,
note:volInstance.volNote,
recommendation:volInstance.recommendation,
discovered:volInstance.dateFound,
url:volInstance.urlParam]">
Create Another like this
</g:link>
and then doing a lot of <g:if> on the next create.gsp to see if the parameters are present. I then advanced to just sending the instance id as a param
<g:link class="create" action="create"
params="[vid:volInstance.id]">
and changed the create method in the controller. This simplified things (no longer have a huge params list):
def create() {
if (params.vid) {
def id = params.vid
def v = Vol.findById(id)
params.volNote = v?.volNote
params.volType = v?.volType
etc......
}
respond new Vol(params)
}
This works nicely and eliminates all the <g:if>s but still have a lot of lines of params.x = v.x
would there be a way to get rid of those lines and just pass the object as a param?
Looks like a good place for a Command Object. You can declare it in your controller, and then pass it as an argument to your action. You can even add validation if you want.
class MyCommand {
Long id
String volNote
String volType
static constraints = {
volNote (blank: false)
//...
}
}
Then in your action:
def create(MyCommand cmd) {
Long id = cmd.id
//...
I have already posted this question, but i realised the aswer was not what i was looking for. Imagine this controller:
class exampleController{
def action1 = {
...
[lala: lala, lele: lele]}
...
}
def action15 = {
...
[lala: lala, lele: lele]
}
I want to be able to return in all the action in this controller the same params. Imagining this:
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
Is there any way of doing this, besides writing all the same code on all the actions? I have tried this method and it isnt working:
def action5 = {getModel()}
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]. Any suggestion please ? I have also tried filters like in here: Grails controllers repeated code for all actions
but i couldnt managed to make it work. I would apreciated a detailed explanaintion about any of the solutions if possible:p Thanks in advanced,
VA
So it's not the same model, but a model with a repeated part.
You should know that the return value is an ordinary Map.
So, return value can be constructed like return getCommonModel() + [book: currentBook] where getCommonModel() returns another Map.
If you want to return the same model from all your actions, this approach should work:
class ExampleController {
def action5 = {getModel()}
def action1 = {getModel()}
//etc.
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
If you want to return the same model and render the same view from all your actions, you could return the same ModelAndView from each action, but then I would ask why do you need separate actions if they're all doing exactly the same thing?
I don't really understand your hypothesis
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]
If your suggesting that getModel() can only return a model with a single entry, I find that very hard to believe. Can you elaborate a bit on this, or post some more information (e.g. stacktrace, unit test) that shows how/why it's not working?
Update
After reading your comments below I think I finally understand what you want to achieve, which is to append the model returned by getModel() (above) to the model returned by various other actions. Does this work:
class ExampleController {
def action5 = {
def action5Model = [foo: 'bar']
return addBookModel(action5Model)
}
def action1 = {
def action1Model = [foo2: 'bar2']
return addBookModel(action1Model)
}
//etc.
private Map addBookModel(Map model) {
def book = Book.findAllByIsbn(Isbn.get(1))
model.book = book
return model
}
}
This approach will only work when you want to add the book model within a single controller. If you want to add the book model in several controllers you can do this by:
putting addBookModel in an abstract class that the controllers extend
putting addBookModel in a class that is mixed-in with the controllers (using #Mixin)
putting addBookModel in a filter that is executed after the controller actions
If you are using exact same model in multiple pages. I would recommend you use a taglib for it.
Is it possible to access the current controller instance from within a TagLib? For example:
class FooTagLib {
static namespace = 'foo'
def msg = { attrs, body ->
// Can I get a reference to the current controller here?
}
}
I want to do this because I store some data in a property of the controller and want to access it within the TagLib. I realise this may sound strange, but just humour me....
Inside your msg tagLib:
grailsApplication.getArtefactByLogicalPropertyName('Controller', pageScope.controllerName)
Like Views, you have access to the current controller and action through controllerName and actionName
Try something like this...
def ctl = grailsApplication.getArtefactByLogicalPropertyName('Controller', 'whateverController')