How to nest Grails controller paths - grails

I know it is possible to do something like this:
Controller foo with action bar can be accessed by (1):
/appname/foo/bar
And it can be rewritten using URL mappings - e.g like this:
"/foobar/foo/$action"(controller: "foo")
And then access it via (2):
/appname/foobar/foo/bar
But it is still possible to access it via (1). This is of course because of the default URL mapping:
"/$controller/$action?/$id?"()
But I would rather not delete this, because this basically means I have to manually write mappings to every other controller/action that follows the default pattern.
It is possible to obtain url-patterns for specific controller/actions like (2) without using URL mappings? If not, is there an easy way to "exclude" controllers from the default mapping closure?

The Solution is to change the default mapping, in a way to exclude the whished special controller URL.
class UrlMappings {
static myExcludes = ["foo"]
static mappings = {
"/foobar/foo/$action"(controller: "foo") // your special Mapping
// the rewritten default mapping rule
"/$aController/$aAction?/$id?"{
controller = { (params.aController in UrlMappings.myExcludes) ? "error" : params.aController }
action = { (params.aController in UrlMappings.myExcludes) ? "notFound" : params.aAction }
constraints {
// apply constraints here
}
}
}
}
For the rewritten default rule you have to prevent usage of default variable names $controller and $action. Instead of error/notFound you are also able to redirect to other locations.

If you can make your rule breaking scenario more specific than the Grails default $controller/$action?$id? pattern, then the default can be left as is and will apply to everything outside of your exception pattern. I made a quick Person domain and performed a generate-all. Then I made a BreakRuleController just by itself.
class UrlMappings {
static mappings = {
"/b/$action?/$someVariable?"(controller: "breakRule")
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"500"(view:'/error')
}
}
With this UrlMapping, if you access the URI "/b/foo/stackoverflow" it will print "Breaking Rules foo: stackoverflow". If you go to "/b", it will print "Breaking Rules index".
Then if you go to the standard Person URI's, all your default Grails scaffolding works fine also (create, edit, etc.) because that gets mapped to the typical "$controller/$action?/$id?" pattern.
class BreakRuleController {
def index() {
print "Breaking Rules index"
}
def foo(String someVariable) {
print "Breaking Rules foo: " + someVariable
}
}

Related

Parameterize UrlMappings in Grails 3

I had this idea that I wanted to assign prefixes to my two categories of URLs. One category would be
/baseurl/api/$controller
for secured REST URLs and then:
/baseurl/register/$action
for the current one category of unsecured URLs
I then thought it would be good to store the prefixes /api and /register in variables so they could be referenced elsewhere if need be (such as my security configuration). However, I can't get this to work in my UrlMappings. None of the variables defining the URL parts seem to be populated. Consider the following UrlMappings.groovy where I've defined a SignupController.groovy to map to registration, and every other controller is API related:
class UrlMappings {
static final API_URL_ROOT = "/api"
static final REGISTER_URL_ROOT = "/register"
static mappings = {
API_URL_ROOT + "/$controller/$action?/$id?(.$format)?" {
constraints {
}
}
REGISTER_URL_ROOT (controller: "signup")
"/"(view: "/index")
"500"(view: '/error')
"404"(view: '/notFound')
}
}
When this runs I can only invoke my controllers through the root URL directly, ie, localhost:8080/login and localhost:8080/signup whereas I want it to be:
localhost:8080/api/v1/login and localhost:8080/register/signup
How do I fix this?
You could use group to separate your different api
http://mrhaki.blogspot.com/2013/11/grails-goodness-grouping-url-mappings.html?m=1
In your case it could become something like that
group("/api") {
"/$controller/$action?/$id?(.$format)?" { constraints { } }
// PUT HERE ALL OTHER API MAPPING
}
group("/register") {
"/$controller" {}
// PUT HERE ALL REGISTER MAPPINGS
}
If you need to take into consideration a version for your api just do this
group("/api") {
"/$namespace/$controller/$action/$id?" {}
// OR ANY OTHER MAPPING YOU NEED. Then in your controller define
// static namespace = 'v1'
// for example for your v1 controllers.
}
Then you can declare you groups as variables if you want.
static API="/api"
group (API) { .... }
Hope that helps if not sorry for the noise

How can I use path variables in grails controller?

I have been trying to use a path variable in grails controller but I am not able to achieve it.
The intention behind is to validate the parameter submitted to the url which I need to make mandatory. I could not achieve it through RequestParam so I switched to PathVariable so that the url submitted without the required param should be filtered off by grails controller itself rather than me adding if/else checks for validity.
So, I can illustrate as below:
My URL is something as below:-
'<appcontext>/<controller>/<action>?<paramName>=<something>'
Now, to make 'paramName' mandatory I am not finding any way in Grails(Spring MVC provides #RequestParam annotation which can enable me for 'required' as true).
Another alternative I thought was to use path variables so that 'paramName' can be included in URL itself. So I tried like following:
'<appcontext>/<controller>/<action>/$paramName'
For validating the above URL I wrote specific mapping but some how it does not work too..
Following is the specific mapping I wrote:-
"/<controllerName>/<action>/$paramName" {
controller:<controller to take request>
action:<action to do task>
constraints {
paramName(nullable: false,empty:false, blank: false)
}
}
I tried to use spring annotation like #PathVariable and #RequestParam in controller as given below:-
def action(#PathVariable("paramName") String param){
//code goes here
}
If you name the method argument the same as the request parameter rename, Grails will take care of it for you...
// In UrlMappings.groovy
"/foo/$someVariable/$someOtherVariable" {
controller = 'demo'
action = 'magic'
}
Then in your controller:
// grails-app/controllers/com/demo/DemoController.groovy
class DemoController {
def magic(String someOtherVariable, String someVariable) {
// a request to /foo/jeff/brown will result in
// this action being invoked, someOtherVariable will be
// "brown" and someVariable will be "jeff"
}
}
I hope that helps.
EDIT:
Another option...
If for some reason you want different names for the method arguments you can explicitly map a method argument to a request parameter like this...
import grails.web.RequestParameter
class DemoController {
def magic(#RequestParameter('someVariable') String s1,
#RequestParameter('someOtherVariable') String s2) {
// a request to /foo/jeff/brown will result in
// this action being invoked, s2 will be
// "brown" and s1 will be "jeff"
}
}

How to restrict properties for a domain being set from params

I've got several properties in my domain class. However, I only want few of them to be set via the params object. What is a good way to do this?
Example:
Domain
class Color {
String name
String shade //don't want this set by params
}
controller
class ColorController {
def save() {
json {
def c = new Color(params?.color)
c.save(flush: true)
//..more code
}
}
}
If someone sends a request like:
{"color":
{name: "red",
shade: "light"
}
}
then user can change the shade property. How can I stop this?
You could probably do one of a couple of things:
If it is many properties, create a transient beforeInsert() {} and/or transient beforeUpdate() {} method in your domain class and handle setting (or not) the properties.
If only a few, override the setters in the domain class.
Since Groovy makes me not want to mess with getters and setters unless I absolutely have to, I usually use the beforeInsert and beforeUpdate methods.
Grails provides a bindData method on the controller to give you fine grained control of data-binding. For your example you could write this as:
class ColorController {
def save() {
json {
def c = new Color()
bindData(c, params, [include: 'name'])
c.save(flush: true)
//..more code
}
}
}
In this case, only the 'name' field would be set on the c instance before attempting to save.
If you want to to additional validation on the incoming params, I would also suggest looking into using a Command Object for the data binding.

Making Grails controllers more DRY?

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.

decorate Grails tag

The taglib provided by the Grails bean fields plugin uses a naming convention to determine the label key that should be used for each <input> element it generates. I would like to change the details of this convention without changing the plugin's source code directly.
The approach I'm considering is to create my own tag lib
class MyBeanTagLib {
static namespace = 'mybean'
private void setLabelKey (attrs) {
if (!attrs.labelKey) {
// in reality calculation of the default key is a bit more complicated :)
attrs.labelKey = 'my.default.key'
}
return attrs
}
// renders a combo box
def select = { attrs ->
attrs = setLabelKey(attrs)
// Now call the bean-fields select tag, passing along attrs
}
// renders a datePicker
def date = { attrs -
attrs = setLabelKey(attrs)
// Now call the bean-fields date tag, passing along attrs
}
}
My first question is how to invoke the tag I'm trying to decorate. In other words, what code should replace the comment
// Now call the bean-fields...
I could do this:
new BeanTagLib().select(attrs)
But I doubt this is the correct way to invoke one taglib from another.
Secondly, is there a more elegant way to decorate a taglib than this? In reality there are a lot more tags than just select and date that I need to decorate and the code in each decorating tag will be almost identical. I'd like to eliminate this duplication if possible?
Invoke other taglibs' tags by their namespace, like g.link([controller: 'one'], { 'link text' }), or bean.select(attrs).
You can try writing getProperty in your taglib and return proper closures - I'm not sure.

Resources