Accessing a Groovy controller closure from another controller - grails

In our codebase we have a closure in a controller that looks like this:
def doComputation = {
def someObject = SomeObject.read(params.long("objectId"))
//some irrelevant logic
def response = [importantVariable : importantInteger, someOtherVariable : someOtherInteger]
render response as JSON
}
Of course this is generally called from the .gsp page, but is there a way to call it from a closure in a different controller? Like so:
def someOtherClosure = {
//some more irrelevant logic
def responseFromOtherClosure = doComputation(objectId : someLong)
theValueIWant = responseFromOtherClosure.importantVariable
//more logic
}

but is there a way to call it from a closure in a different
controller?
There is.
The closures are just properties in the controller class and they are public. Controllers are configured as Spring beans so you could (you shouldn't) inject a controller into another controller and then reference the closure properties from there.
I think that answers your question but there are no good reasons to do that. The right solution will depend on some particulars but if you have 2 controller actions that need to share some logic, best practice is to move that logic into a service and inject that service into all the controllers that need it.
Depending on what you are trying to accomplish, instead of invoking a controller's code directly from another controller (again, no good reason to ever do that) you might want the first controller to issue a redirect or a forward which will lead to the second controller.

Related

How do I call a method on one controller from another in .NET 4 MVC

In an asp.net MVC application, I need to produce some documens, HTML and PDF, which are not sent to the user's browser, but either sent by mail or entered in our document journalizing system. I produce these documents using Razor.
When a document is used only once, I just add a method to the relevant controller, and the view to that controller's view folder. This works. But I have a document that must be produced at two places in the application, implemented in separate controllers. I have made a new controller for this document with its own view folder.
My question is now: how do I call a method on this controller? Searching the web gives many answers, but all redirect the user to this document, which is not what I need.
You can just call it like you would any other method e.g.
public ActionResult DoSomething()
{
// Some code
var otherController = new OtherController(); // The other controller where the method is
otherController.CreatePdf(); // Call the method
// Continue with what ever else you need to do
return View(); // This will then return the `DoSomething` View
}
But personally it doesn't seem like this logic belongs in a controller. You should possibly think about refactoring this logic out of a controller and into a more logical place. Possibly create your own document generation class and use that.
If I'm getting you right.You could create a base controller and add the method there. You can inherit the Base controller in any controller where you want to call the method. here's a link that might help show you the use of Base controllers. How to wire common code from a base controller in ASP.NET MVC.

Calling a Controller Action from a View... Or not?

I'll keep it short: Should I call Controller2.getByCriteria(some, criteria, here) from Controller1 then set an instance variable for the view to use, or should I call it from Controller1's view using something like = render Controller2.getByCriteria(some, criteria, here)?
Generally speaking, calling one controller's action from another is a design error. It either means you have common business logic, which implies the code should be in models (or maybe lib) or you have common view logic, which implies the code should be in helpers.
So in your case, I think using a helper seems apt:
module ApplicationHelper
# ...
def getByCriteria(some, criteria, here)
# handle criteria here
# Something like:
# render :partial => 'foo'
end
# ...
end
And then simply call it from the views.
If you want a full controller/view like component sharing across your application, you can use a gem called cells. It enables you to create re-usable controller and view components.
The proper way to do this is to declare the controller method (not controller action) as a helper.
See here.

Which way of mapping action class to request is recommended?

In struts 2, the action to class mapping can be done in 2 ways:(Please pardon the wrong syntax)
action = "action1" class = "class1" results = "results1"
action = "action2" class = "class2" results = "results2"
and so on for each action = 1 , 2 ....n i.e. 1 action class per request
Or:
action = "action1" class = "class1" results = "results1" method = "method1"
action = "action2" class = "class1" results = "results1" method = "method2"
and so on. i.e only 1 action class for all requests. But each action has a separate method.
Is there any best practice which to use when?
Think of it as you would a general Java problem. Should I create a new class to address this issue or should I create a new method to address this issue? That is, is this a new thing or better expressed as a behavior of an existing thing.
If you have a page which will display employees, then that deserves an action class. If you have another page that displays companies, that deserves another action class. I like to put CRUD and certain Ajax features into the same class because I think I move around less that way.
It wouldn't however make sense to have one action class loaded with methods mashing together unrelated ideas, well it wouldn't be Java thinking anyways.
Really one action to one class is a personal preference thing but I think you should be consistent what ever you do. Projects that don't require much crud or ajax perhaps would use methods as actions so rarely that perhaps it would be better to just consistently avoid them.

ASP.NET MVC: How to handle model data that must go to every view?

So if there is some global state that every view of an MVC app will need to render ... for example: IsUserLoggedOn and UserName ... whats the appropriate way of getting that information to every view?
I understand that that part of the view should be in the master page or in a partial view thats added to the other views. But whats a good way to make sure the 'global' model data is passed to the view every time from all the relevant controllers and actions?
After asking this, I found this good blog post by Steve Sanderson:
http://blog.stevensanderson.com/2008/10/14/partial-requests-in-aspnet-mvc/
He suggests three different approaches:
Use a base controller class or ActionFilter to add the relevant model to the ViewData[] collection every time. I think a few people have suggested that sort of thing already.
Use Html.RenderAction() in the view ... and as he says:
If someone tells you that internal
subrequests are bad because
it “isn’t MVC”, then just bite them on
the face immediately. Also ask them
why they’re still willing to use Ajax,
and even <IMG> tags for that matter,
given that both are a form of
subrequest.
Use 'Partial Requests' (he provides the code for this on his blog) which allow one controller to nest calls to other controllers into a sortof nested ViewData structure.
codeulike - see the answer to a similar question asked at exactly the same time as this:
ASP.NET MVC displaying user name from a Profile
in a nutshell, basically create a base controller that's inherited by all your other controllers. the base controller then has an override function that carries thro' to all 'child' controllers. rather than duplicate the code, take a look at my answer above and give it a try..
cheers...
You could create base class for viewmodel which contains shared information and inherit that for each viewmodel.
public class ViewModelBase
{
// shared data
}
public class Page1ViewModel : ViewModelBase
{
// page 1 data
}
In masterpage you could use that base class
Inherits="System.Web.Mvc.ViewMasterPage<ViewModelBase>"
and in each view use those derived classes
Inherits="System.Web.Mvc.ViewPage<Page1ViewModel>"

ASP.NET MVC: Uses a delegate field as an action method?

Is it possible in ASP.NET MVC via some extension/override points to allow a "delegate field" to be used as an "action"?
Something like:
using System;
using System.Web.Mvc;
namespace Company.Web.Controllers
{
public class SwitchboardController : BaseController
{
public Func<ActionResult> Index, Admin, Data, Reports;
public SwitchboardController()
{
// Generic views
Index = Admin = Data = Reports =
() => View();
}
}
}
I know I'm a little hell-bent for this one but if this is possible it'd open up many new ways of making actions. You could, for example, have Django-style generic views in MVC with only a single line of code to define the action or have different ways to factor duplicate logic across multiple controllers.
I'm not quiet sure where would be the place to slap this logic into or how much work would be required to alter something so fundamental in the framework.
You will probably have to build your own Controller factory. This class builds controllers, and implements IControllerFactory. You can inherit from DefaultControllerFactory. Override CreateController() to return your own IController.
Register your controller factory in Application_Start() of MvcApplication using this line:
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
In your implementation of IController, override the Execute method. You can use the RequestContext to decide which delegate to invoke. It would probably be easiest to inherit from ControllerBase, and override Execute in there if you don't want to fully implement IController.
The RequestContext passed into Execute carries a RouteData object. This is a dictionary populated by the routing engine that tells you what action should be invoked, and any parameters. You can get the action name like this:
//context is a RequestContext object passed to IController.Execute()
string actionName = requestContext.RouteData.Values["action"];
You could even define your action as a dictionary, and just pull them out once you get the action name.
One last thing, normal action methods return an ActionResult, which the framework uses to decide which view to render. Once you execute your delegates, I think you'll have to set some stuff manually in your special base controller. I'm not exactly sure what to set or how to get your View executed from here without cracking open the MVC source.
Good luck! This looks like an interesting idea.
As you seem to be implementing a BaseController in your code sample, if you override the Execute (from the IController) you'll be able to interpret the request => action however you like.
No, it isn't. The base controller is looking for methods and not for fields to dispatch an action.
EDIT:
Sorry, I was a bit fast and fixed to the standard classes provided.
You can do that but you have to overwrite the Execute Method in your controller or implement and provide your own IActionInvoker to dispatch the action to fields. Look into the post action processing in detail. It explains the dispatching in detail.

Resources