From what is in the Grails user guide, the recommended way to send different content formats based on the content negotiation is to use a withFormat block:
import grails.converters.XML
class BookController {
def list() {
def books = Book.list()
withFormat {
html bookList: books
js { render "alert('hello')" }
xml { render books as XML }
}
}
}
However, I would like the responses of ALL my controller methods to do this. Is there a better way to get this behavior than to simply copy-paste the withFormat block at the end of every content-returning action?
First two things that popped in my head were Interceptors and Filters:
http://grails.org/doc/1.3.7/ref/Controllers/afterInterceptor.html
http://grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.6 Filters
Interceptors won't work because you can't do the withFormat. Bummer because that's a more global.
Filters will work on a controller per controller basis, but at least you'd be minimizing your duplication at that level.
def afterInterceptor = {model, modelAndView ->
withFormat {
html { model }
js { render "alert('hello')" }
xml { render model as XML }
}
}
This worked for me in my test project. I tried putting that closure into it's own class and mixing in the class so that you could do a more global solution... no dice though.
Maybe have all of your afterInterseptors pass the model, modelAndView to a common class? That seems to work :) (working towards an answer while answering)
#Mixin(AfterInterceptorWithFormat)
class FirstController {
def action1 = {}
def action2 = {}
def afterInterceptor = {model, modelAndView ->
performAfterInterceptor(model, modelAndView)
}
}
class AfterInterceptorWithFormat {
def performAfterInterceptor(model, modelAndView) {
withFormat {
html { model }
js { render "alert('hello')" }
xml { render model as XML }
}
}
}
Give that a whirl and let me know what you think.
What I ended up doing is to simply adjust the default CRUD templates to have the withFormat block at the end of each method.
I realized that what I really wanted was just content-negotiated CRUD, so putting the code into the templates was all I needed for that.
The rest of the controllers for the non-crud parts of my application did not need no-html output, so I didn't need content negotiation on anything but the crud controllers.
Related
In grails controller examples, I have seen save(Model modelInstance) and save(). I tried them both, both of them works. I imagine grails instantiates the modelInstance with the params. Is my assumption correct?
I also noticed in index(Integer max), does the param has to be named max? or any name would work as long as it is a number?
How does these passing of arguments work underneath?
If you write a controller like this...
class MyController {
def actionOne() {
// your code here
}
def actionTwo(int max) {
// your code here
}
def actionThree(SomeCommandObject co) {
// your code here
}
}
The Grails compiler will turn that in to something like this (not exactly this, but this describes effectively what is happening in a way that I think addresses your question)...
class MyController {
def actionOne() {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
// Grails generates this method...
def actionTwo() {
// the parameter doesn't have to be called
// "max", it could be anything.
int max = params.int('max')
actionTwo(max)
}
def actionTwo(int max) {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
// Grails generates this method...
def actionThree() {
def co = new SomeCommandObject()
bindData co, params
co.validate()
actionThree(co)
}
def actionThree(SomeCommandObject co) {
// Grails adds some code here to
// do some stuff that the framework needs
// your code here
}
}
There is other stuff going on to do things like impose allowedMethods checks, impose error handling, etc.
I hope that helps.
The project I'm working on currently uses filters for various pieces. The filters themselves work great. The problem I'm running into is that when specifying which controllers the filter should be executed on, I end up with a very large list. Functionally this works fine but it ends up being ugly and somewhat unwieldy.
def filters =
{
filterSomething(controller:'one|two|three|...|xyz', action:'*')
{
//before filter here, not important.
}
}
Is there a way to specify that the filter is only applicable for controllers in a given package or list of packages?
If there is nothing out of the box, I was thinking about tying something into the bootstrap and setting my lists that way.
You could have a filter on all controllers and then check their package and then decide what you want to do. There are better and more elegant way coding this, but just to give you an idea.
class MyFilters {
def grailsApplication
def filters = {
all(controller:'*', action:'*') {
before = {
if (checkController(['com.package.name'],controllerName)){
}
}
}
}
def searchInList(list,packageName){
for (keyword in list) {
if (packageName.contains(keyword)) return true
}
return false
}
Boolean checkController(def includePackageList,cname) {
def dlist = grailsApplication.getArtefacts("Controller")
def filteredList= dlist.findAll{ searchInList(includePackageList,it.getPackageName()) }
return filteredList.contains(cname)
}
}
I've to display check box checked or not based on some logic which is more than 4 lines of groovy code ...
I don't like to write it in GSP page..is there any taglib or some way I can extract the logic out of GSP page.
where I could access model boject and request objects.
You have (at least) 3 options:
Model attribute
If you're only doing the complex logic for a single page or a single controller, do the logic in the controller method and pass the boolean result to the view through a boolean:
// in your controller
def myAction() {
[shouldDrawCheckbox: shouldDrawCheckBox(...)]
}
private boolean shouldDrawCheckBox(/* info for decision making */) {
// decision making
}
Service method
If you're going to access this identical logic from several controllers, you can extract the shouldDrawCheckBox method into a service and again pass the result through the models.
class MyController {
def myService
def myAction() {
[shouldDrawCheckbox: myService.shouldDrawCheckbox(...)]
}
}
class MyService {
boolean shouldDrawCheckBox(...) {
// logic!
}
}
Custom Taglib
If you want to avoid passing the decision through the model, or if the logic is more generally applicable, you can create a custom taglib.
class MyTaglib {
static namespace = "my"
def myCheckbox = { attrs ->
// extract decision info from the attrs
// perform logic with info
if (shouldDrawCheckbox)
out << g.checkbox(attrs: attrs)
}
}
}
In your view:
<my:myCheckbox whateverYourAttribsAre="value" name="..." value="..."/>
A TagLib is a good palce to put your logic, you can pass what you need as attributes and do your test:
class MyTagLib {
static namespace = "my"
def somecheckbox= { attrs ->
def model = attrs.remove('model')
if() { //tests goes here
//you can also test if you need to mark the checkbox as checked
if() {
attrs.checked = "checked"
}
out << g.checkbox(attrs: attrs) //remaining attrs will be applied to the checkbox
}
}
}
myview.gsp
<my:somecheckbox model="${model}" name="checkboxname" value="${checkboxValue}" />
Ideally the logic should go to the controller which renders the gsp and sets a flag in the model object. If the gsp is a child of a template, then the flag has to pass through. DOM manipulations in view layer is not ideal when we have appropriate binding framework available in grails.
Use the g: namespace. http://grails.org/doc/2.2.x/ref/Tags/checkBox.html
<g:checkBox name="myCheckbox" value="${condition}" />
It doesn't get any simpler then this. All the logic should be done inside the controller.
All the data you need on a page can be passed by the controller. Just return a Map.
class MyController {
def index() {
def someCondition = true
[request:request, condition:someCondition]
}
}
Take the following controller:
package test
class TestController {
static defaultAction = "test"
def test() {
render "test"
}
}
Why is test defined with def test() { instead of something like void test() {? Isn't the def keyword only used for closures or functions in a script (i.e. not in a Groovy class)?
render is void so in this case the test action could be void, but in the case where you return a model map the action has to be non-void:
def create() {
[personInstance: new Person(params)]
}
Since some actions can return a value and some don't, the general syntax has to return def to support all variants.
Burt's answer is correct but the real problem I was having is that I misunderstood what def is. Rather than being like var in JavaScript, you can think of it like Object in Java.
I thought that using def was like doing (JavaScript)
var test = function() {
alert("test");
}
while in reality it's just like (Java)
public Object test() {
return someObject;
}
It's not a different kind of function/closure, it's like a return type—def can be applied to any object (Groovy has no data primitives, so any value is also an object, unlike in Java).
It helps my Java brain to think of
def bar = "foo";
as
Object bar = "foo";
I am looking for ways on how to cleanup my Grails controller code. In various controllers i more or less have the same logic..
get the object
check if it exists
etc..
Is there a suggested way on making controller actions reuse common code?
--- solution ---
All answers to the question have contributed to the solution we have implemented.
We created a class that is used in our controllers using the Mixin approach. One of the methods that the mixin exposes is the withObject method. This method takes the domainname from the controller and uses this a base for the method. This behaviour can be overridden of course!
def withObject(object=this.getClass().getName()-"Controller", id="id", Closure c) {
assert object
def obj = grailsApplication.classLoader.loadClass(object).get(params[id])
if(obj) {
c.call obj
} else {
flash.message = "The object was not found"
redirect action: "list"
}
}
So all answers have contributed to the solution! Thanks a lot!
I always pull out this blog post when this question comes up:
http://mrpaulwoods.wordpress.com/2011/01/23/a-pattern-to-simplify-grails-controllers/
Basically you have a private helper for various domains in your controllers.
private def withPerson(id="id", Closure c) {
def person = Person.get(params[id])
if(person) {
c.call person
} else {
flash.message = "The person was not found."
redirect action:"list"
}
}
The way you code the getter is very flexible and a typical use for me (that is not covered in the blog) is for editing etc.
I normally code this way (i like the pattern for its clear division and readability):
def editIssue() {
withIssue { Issue issue ->
def issueTypes = IssueTypeEnum.values().collect {it.text }
[issueTypes:issueTypes,activePage:"issue", issue: issue]
}
}
def doEditIssue(IssueCommand cmd) {
if(cmd.validate()) {
withIssue { Issue issue ->
issue.updateIssue(cmd)
redirect(action: "show", id: issue.id)
}
}
else {
def issueTypes = IssueTypeEnum.values().collect {it.text }
render(view: "edit", model:[issueTypes:issueTypes,issue:cmd,activePage:"issue"])
}
}
With my getter helper being:
private def withIssue( Closure c) {
def issue = Issue.get(params.id)
if(issue) {
c.call issue
}
else {
response.sendError(404)
}
}
I do think that the mixin method (very similar to the 'extend a common abstract controller' way) is nice too, but this way gives two advantages:
You can type the helper, like you see I do in the closure giving you access to the methods etc in STS/IDEA (not tested Netbeans)
The repetition is not very high, and the ability to change the getter (to use for example BarDomain.findByFoo(params.id) etc)
In the view I bind to edit() I just put an id="${issue.id}" in the <g:form> and it works seamlessly.
I wouldn't recommend inheritance for that, as you can't spread generic methods in several super classes. Your abstract class would quickly become messy if you have many controllers. You can't use composition (for instance using a Service) because you don't have access to response, render, or params directly from there.
The approach I use is to inject generic methods via Mixins.
#Mixin(ControllerGenericActions)
#Mixin(ControllerUtil)
class BookController {
def show = &genericShow.curry(Book)
def exists = {
render(idExists(Book))
}
}
The first action show uses a generic method in ControllerGenericActions.groovy, with an argument binded to it. The second use of a mixin idExists method is inside a controller action.
Here is an example code for src/groovy/ControllerGenericActions.groovy
class ControllerGeneric {
def genericShow(Class clazz) {
render clazz.get(params.id) as XML
}
}
and in src/groovy/ControllerUtil.groovy
class ControllerUtil {
def idExists (Class clazz) {
return clazz.get(params.id) != null
}
Not very useful in this case, but you get the idea.
Implement abstract controller with common methods (use 'protected' directive) and extend from it your real controllers. Do not use 'get' and 'set' words at the beginning of this method's names. Not good, but it works.