grails access controller from taglib - grails

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')

Related

How can i respond to the same gsp view from the controller?

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.

implement "create another like this" functionality in grails

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
//...

Redirect from a method in a class to an action result in a controller

I have a mvc application and when a user is authenticated,
a method is called from a class to determine the type of user.
I will like to do a redirect to an action result in a controller from a method in a class.
How do i redirect from a method in a class to an action result in a controller?
There might be a good reason for why you want to do it this way, but I want to suggest an alternative for you.
I would suggest that you redirect to an action based on the result from a method in a class, rather than doing the redirection in the method itself.
Pseudo-code:
public ActionResult Index()
{
var tmp = new YourClass();
if(tmp.UserType().Equals("Admin")
{
return RedirectToAction("Admin", "Home");
}
if(tmp.UserType().Equals("User"))
{
return RedirectToAction("User","Home");
}
}
First off, I think it's not a good practice to call controller actions from classes like you wish.
Your class will be tightly coupled to an MVC controller.
However it's feasible by doing this:
var context = new RequestContext(
new HttpContextWrapper(System.Web.HttpContext.Current),
new RouteData());
var urlHelper = new UrlHelper(context);
var url = urlHelper.Action("Index", new { OtherParm = "other value" });
System.Web.HttpContext.Current.Response.Redirect(url);
this example comes from this answer

getting a particular instance on a domain in grails

I have one gsp file which calls a method like this:
<g:link id="${child.id}" action="callChildProfile" controller="profile">${child.firstname}</g:link>
which calls this method
def callChildProfile(Long id){
childInstance = Child.get(id)
System.out.println(childInstance.firstname + " child instance")
redirect(action: "index")
}
this method set a child instance to a public variable called child instance but when the redirect happens the variable is reset.
The reason I redirect is because I want to load up the index page from this controller.
Index looks like this:
def index() {
def messages = currentUserTimeline()
[profileMessages: messages]
System.out.println(childInstance + " child here")
[childInstance : childInstance]
}
By default controllers are prototype scoped, which means the instance of ProfileController used will be different between the request which calls callChildProfile and the request which calls index. Thus, the object level childInstance variable won't be available between requests.
To use the Child instance in the index call, look at the chain method:
callChildProfile(Long id){
// do usual stuff
chain(action:"index", model:[childInstance:childInstance])
}
def index() {
// do other stuff
[otherModelVar:"Some string"]
}
When returning a Map from index the model of the chain call will be automatically added, so your childInstance from the callChildProfile will be available for the gsp.
Variables in controller methods (actions) have a local scope, thus, only can be used in that method. You should pass the id from new instance and use that id for retrieve the object.
redirect action: "index", id: childInstance.id
and index could be
def index(Long id){
childInstance = Child.get(id)
Then you can conclude that you don't need the callChildProfile method
or you can use params
def index(){
childInstance = Child.get(params.id)
if(childInstance){
doSomething()
}
else{
createOrGetOrDoSomethingElse()
}
}

Adding a variable to all views in grails

I am trying to set a variable for the current user (a POJO) in all views so I can get things like the user name and check their role on every view (including the default layout). How can I setup something (e.g. currentUser) in grails so that it is accessible in every grails view like so:
<div>${currentUser.name}</div>
or like this:
<g:if test="${currentUser.admin}">ADMIN</g:if>
You want to use a grails filter. Using a filter, you can specify which controllers and methods (using wild cards) you want to intercept using before/after and afterView methods.
This makes it easy to stuff a new variable into the model so it's available in a view. Here's an example that uses the acegi plugin authenticateService:
class SecurityFilters {
def authenticateService
def filters = {
all(controller:'*', action:'*') {
after = { model ->
def principal = authenticateService.principal()
if (principal != null && principal != 'anonymousUser') {
model?.loggedInUser = principal?.domainClass
log.debug("SecurityFilter: adding current user to model = $model")
} else {
log.debug("SecurityFilter: anonymous user, model = $model")
}
}
}
}
}
You can use the session scope to store the variable. Your calls would change to:
<div>${session.currentUser.name}</div>
and
<g:if test="${session.currentUser.admin}">ADMIN</g:if>
And you would set the variable like so in a controller:
session.currentUser = XXXXX

Resources