I set up namespaces in my UrlMappings.groovy as:
"/usa_az/$controller/$action/$id?(.${format})?"(namespace: 'usa_az')
"/usa_ms/$controller/$action/$id?(.${format})?"(namespace: 'usa_ms')
Is there a way to do something like:
class NameSpaceInterceptor {
NameSpaceInterceptor(){
matchAll() //match all controllers
}
//Change the name of the view to find it in state-specific folder in views
boolean after() {
if(*controller.namespace* == 'usa_az' ){
view = "/usa_az/$view"
} else if (*controller.namespace* == 'usa_ms' ){
view = "/usa_ms/$view"
}
true
}
}
How do I find the handle to controller or more importantly the namespace in this interceptor?
I actually did something along the lines of this:
boolean before() {
if (controllerNamespace == "admin") {
}
}
in one of my interceptors, so the answer should be via controllerNamespace.
Related
Here is what I'm trying to achieve. Certain options at the navbar should be available only if the user has "subordinates" in the database.
So, at the navbar I have:
The Approvals should be hidden for some users, but available to others. For those whom it should be available, the user must:
A) Be a Supervisor or,
B) Have a subornidate at the DB table
So, as for "A" it's pretty straightforward. I did:
#if (User.IsInRole("Supervisor"))
{
<li>#Html.ActionLink("Approvals", "Index", "Approval")</li>
}
For "B", I was suggested to use Sessions. Well, great. So I came to the question: how can I make a single request to the DB and assign it to a Session["HasSubordinates"] so I can do this check?
#if (User.IsInRole("Supervisor") || (bool)Session["HasSubordinates"])
{
<li>#Html.ActionLink("Approvals", "Index", "Approval")</li>
}
What I tried was to have:
Session["HasSubordinates"] = _uow.ApprovalService.GetSubordinates(User.Identity.Name).Count() > 0;
for every single controller, but that didn't worked well because sometimes I get null pointer and it looks absolutely rubbish.
I know it may sound like a trivial question for some (or most), but I'm really stuck and I do really appreciate any help.
Looking at your code, getting a user subordinates should only happen once. In your Login method:
Session["HasSubordinates"] = _uow.ApprovalService.GetSubordinates(User.Identity.Name).Count() > 0;
Create a new class to extend IPrincipal:
public class IPrincipalExtensions
{
public bool HasSubordinates(this IPrincipal user)
{
return Session != null && Session["HasSubordinates"] != null && Session["HasSubordinates"] > 0;
}
}
Now, in the View:
#if (User.IsInRole("Supervisor") || User.HasSubordinates() )
{
}
Writing from memory, may have left something out, but this should be the cleanest.
Don't use the session for this. What you need is a child action.
[ChildActionOnly]
public ActionResult Nav()
{
var model = new NavViewModel
{
IsSupervisor = User.IsInRole("Supervisor");
HasSubordinates = _uow.ApprovalService.GetSubordinates(User.Identity.Name).Count() > 0;
}
return ParialView("_Nav", model);
}
Then, just create a partial view, _Nav.cshtml and utilize the properties on the view model to render your nav however you like.
If you want, you can even use output caching on the child action, so it's only evaluated once per user. There's no built-in way to vary the cache by user, so first, you'll need to override the following method in Global.asax:
public override string GetVaryByCustomString(System.Web.HttpContext context, string custom)
{
var args = custom.ToLower().Split(';');
var sb = new StringBuilder();
foreach (var arg in args)
{
switch (arg)
{
case "user":
sb.Append(User.Identity.Name);
break;
case "ajax":
if (context.Request.Headers["X-Requested-With"] != null)
{
// "XMLHttpRequest" will be appended if it's an AJAX request
sb.Append(context.Request.Headers["X-Requested-With"]);
}
break;
default:
continue;
}
}
return sb.ToString();
}
With that, you can then just decorate your child action with:
[OutputCache(Duration = 3600, VaryByCustom = "User")]
I am trying to map the following
//localhost:8080/user/login/&debug=1
...
//localhost:8080/user/&debug=1
If there is any occurrence of string '&debug=1' then execute some-controller's action.
You can use a filter to do the redirect when required.
class DebugFilters {
def filters = {
debugCheck(controller: '*', action: '*') {
before = {
if (params.debug == '1') {
redirect(controller: 'some', action: 'debug')
return false
}
}
}
}
}
If you want to just switch between controllers and actions for a particular url mapping then you can also use a url mapping as below, instead of the filter altogether:
//UrlMappings.groovy
"/user/login" {
controller = { params.debug == '1' ? 'some' : 'user' }
action = { params.debug == '1' ? 'debug': 'index' }
// Note the use of a closure in ternary operations
// params is available in a closure (delegated)
// because it is not available in by default
}
You could use a URLMapping like this
"/**&debug=1"(controller:"defaultDebug"){
action = [GET: "show"]
}
By using the double wildcard you can catch anything that ends with &debug=1
I am updating a library that uses Autofac so that, in addition to the original configuration file (registered via Autofac), it can optionally take a function to accomplish that same goal (again, registered via Autofac). The original is something like this:
public MyClass(ConfigFile config = null)
{
this._activatorLoader = a => {
// old config code here...
}
}
The updated version I'd like is:
public MyClass(
Func<Input, IList<Activator>> activatorLoader = null,
ConfigFile config = null)
{
if (activatorLoader != null)
{
this._activatorLoader = activatorLoader;
}
else
{
this._activatorLoader = a => {
// old config code here...
}
}
}
The problem is that Autofac is seeing my request for a list of something and always providing the function. I tried switching to a delegate and get the same problem:
public delegate IList<Activator> ActivatorLoader(Input input);
public MyClass(
ActivatorLoader activatorLoader = null,
ConfigFile config = null)
{
if (activatorLoader != null)
{
this._activatorLoader = activatorLoader;
}
else
{
this._activatorLoader = a => {
// old config code here...
}
}
}
The loading of the activators must still be delayed, I'd like the flexibility of registering any function based on the situation, and old code (without an activator loader registered) should still work. Is there any way to prevent Autofac from autogenerating the Func?
The class will be instantiated through dependency injection in another class. At a later time, the activator loading code will be triggered (if needed).
var myObject = conatiner.Resolve<MyClass>();
// time passes...
myObject.DoActivatorLoading();
The primary goal is to prevent Autofac from creating the Func<Input, IList<Activator>> if it is not explicitly set. Is this possible?
Perhaps, it will be easier to create a separate class for activator loading ?
public class ActivatorsLoader
{
public IList<Activator> Load(Input input)
{
///
}
}
///
public Class(
ActivatorsLoader activatorsLoader = null,
ConfigFile config = null)
{
///
}
But it would be good to see the use cases of your Class.
I have a URL that I'd like to handle with different controllers depending on the method. Is there a way to do this via UrlMappings?
Using two different mappings for the same URL doesn't work (the second overwrites the first)...
Untested, but can you try with the below mapping:
"/myurl" {
if(params.method == "doThis"){
controller = "doThis"
action = "doThisAction"
} else if(params.method == "doThat"){
controller = "doThat"
action = "doThatAction"
}
}
Assuming,
http://<appserver>/myurl?method=doThis
http://<appserver>/myurl?method=doThat
UPDATE
When referring to HTTP Methods you can use filter (where we have request available) as below:
class RoutingFilters{
def filters = {
routingCheck(uri: '/myurl/**' ) {
before = {
if(request.method == 'GET'){
redirect(controller: 'doThis', action: 'doThis')
}
if(request.method == 'POST'){
redirect(controller: 'doThat', action: 'doThat')
}
//So on and so forth for PUT and DELET
return false
}
}
}
}
provided the url mapping would look something like:
//defaulting to "doThis" or any other "valid" controller as dummy
"/myurl/$id?"(controller: 'doThis')
I made the following rule in my UrlMapping file and now all my controllers are matching to the ("/$username") mapping, not the first one ("/$controller/$action?/$id?").
The idea here was to list all public items from an user using a short url. It works but it breaks all others controllers.
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/$username" {
controller = 'user'
action = 'publicItens'
}
"/"(controller:'usuario', action: 'index' )
"500"(view:'/error')
}
How can I map it correctly?
solved!
I just wrote some code in the UrlMappings to create rules automatically for each controller in the application. Using this approach when the user types /appname/controllerName then the rule created automatically is considered in place of the "$/username" rule.
The critical point is that the use of ApplicationHolder which is deprecated. That can fixed writing your own ApplicationHolder.
static mappings = {
//creates one mapping rule for each controller in the application
ApplicationHolder.application.controllerClasses*.logicalPropertyName.each { cName ->
"/$cName" {
controller = cName
}
}
"/$controller/$action?/$id?"{
}
"/$username" {
controller = 'usuario'
action = 'itensPublicos'
}
"/"(controller:'usuario', action: 'index' )
"500"(view:'/error')
}
Just add /users/$username to the URL mapping. This is the simplest way how to achieve your goals.
"/users/$username" {
controller = 'user'
action = 'publicItens'
}
You could probably also exclude the user and usario controllers in the first url mapping constraints(notEqual)
http://www.grails.org/doc/latest/ref/Constraints/notEqual.html