Many of the available controller methods (chain, forward, redirect) take a map which can include keys such as:
id
params
model
A couple of questions about these:
Is 'id' just an alias for a request parameter named 'id'? In other words, is there any difference between:
chain(controller: "member", action: "showProfile", params: [id: memberId])
and
chain(controller: "member", action: "showProfile", id: memberId)
The chain method (possibly among others) allows passing a model and/or params (map) from controller action A to B. Practically speaking, what's the difference between passing data from action A to B via the params and model maps? Also, if the data is passed in the model map, how do I access it in controller action B?
Everything Burt said is correct. In addition, the reason that you'd want do do a chain (if you have a model) or a redirect (if you don't have a model to keep) is because both of those methods return a 302 redirect response to the browser. The browser then knows to ask for the next page.
It then has the correct url in the header for the resulting page, rather than the url from the page where the original request was from.
This pattern is very useful after a POST of information as it avoids all kinds of trouble with bookmarking, and resubmitting of information if the user hits refresh on the resulting page.
Ex: if you're saving a Book and you want to render the list page if the book is successfully saved. If you just call "controller.list()" in your method, it will show the user the list of books that gets rendered, but the url bar will still say ".../book/save". This is not good for bookmarking or reloading. Instead, calling redirect/chain will send the 302 response to the browser telling it to ask for the ".../book/list" page, which it does. All of your variables (your model and other flash messages) are in flash scope so they're still available to your model/view to use and everything is happy in the world.
This pattern is called Post/Redirect/Get.
'id' comes from UrlMappings entries such as "/$controller/$action?/$id?" - see http://docs.grails.org/latest/guide/single.html#urlmappings for usage.
Params are querystring parameters or form post parameters, accessed in non-Grails apps using "request.getParameter('foo')" but simplified in Grails as "params.foo". The contents of the model map are stored in the Request as attributes, accessed in non-Grails apps using "request.getAttribute('foo')" but simplified in Grails as "request.foo" or more typically accessed directly in GSPs, e.g. "${foo}".
Related
In an MVC project, I have a partial
#Html.Partial("_MyPartial");
which calls a controller method (using AJAX with jQuery) via URL
'/Home/MyActionMethod?type=myType&sort=az&page=1'
The Home controller contains MyActionMethod, which returns a PartialViewResult.
MyActionMethod has parameters matching those in the URL, which are mapped as per usual.
My question is how to access the top level querystring from MyActionMethod, because I want to include extra values in there? By top level I mean the one seen in the browser, as opposed to the one sent to MyActionMethod from _MyPartial
Many thanks
You have to include them as query string parameters when performing your AJAX call. So when building the link on the server, read the query string parameters and append them to those that you have already.
This is a follow-on to an earlier stackoverflow question (link text).
If you use the default routing definition, which ends with {id}, then if you have an ActionLink whose target is the same method as generated the page the ActionLink is on, the framework automagically includes the id in the callback url, even if you didn't request it.
For example, if you're displaying a page from the following URL:
http://www.somedomain.com/AController/SameMethod/456
and the page cshtml file has an ActionLink like the following:
#Html.ActionLink("some text", "SameMethod", ARouteValueDictionary, SomeHtmlAttributes)
then whether or not you have "id" included in ARouteValueDictionary, it will show up in the generated URL.
This only occurs if you call back to the same method that generated the page in the first place. If you call back to a different method on the same controller the {id} field does not get inserted into the generated URL.
I don't necessarily have a problem with this. But I am curious as to why the designers took this approach.
FYI, I discovered this feature because I'd inadvertently been depending on it in my website design. I have to pass the ID field back to the server, along with a bunch of other information...only I'd never explicitly added the ID information to the RouteValueDictionary. But because most of my callbacks were to the same action method that had generated the page in the first place I was having the information included anyway.
You can imagine my surprise when a new component -- which I was sure was "essentially identical" to what was already working -- failed. But because the new component had a different target action method, the magic went away.
Edit:
Modified the explanation to clarify that including the {id} field in the generated URL is contingent upon calling the same method as generated the page in the first place.
...the framework automagically includes the id in the callback url,
even if you didn't request it.
I would prefer the term "ambiently" over "automagically". You can think of route tokens already in the URL as "ambient" to your HtmlHelper and UrlHelpers.
But I am curious as to why the designers took this approach.
Consider a Controller that groups together, say 5 actions. Those 5 may have links to each other, but not a lot of links outside the group. The simplest overload of Html.Action takes only 2 args: the text to render, and the action name.
This makes shorthand for linking around from action to action within these views. Since they are all on the same controller, and that controller is already in the path for the current action, MVC reuses this value when you don't specify the controller name in the helper method. The same behavior extends to {id}, or any other route token you define.
I am creating a Grails application which has an input page with text fields. Here the user can type in the data and on submit, the control goes to the action in controller.
Here I get the value of the form data using params.empName etc.
But the scope of this data is very small and doesnt get carried on if I do a redirect from the current action to another action.
Is there a way to increase the scope of the variables?
I am now to convert this to service oriented architecture. Therefore Is there a way to access these data in the service as well?
Please advice.
Thanks,
Megs
You can add...
params: params
...as an argument to the redirect, so that the incoming params are sent along with the redirect.
I don't think there's a built-in way to increase the scope. This is probably a Good Thing.
If you're redirecting in controllers, you should simply pass along the necessary parameters via the redirect() params dynamic property. Example:
def formHandler = {
// do stuff with params
redirect(action: 'anotherAction', params: params)
}
If you need scope to span multiple requests, e.g. if you're having a multi-step form entry given to the user, you might look into using web flows to persist state between requests.
For services, you're better off just passing down what you need as arguments to the service method, rather than exposing params. Example (similar to the Accessing Services section here):
// service
def myServiceMethod(def foo, def bar) {
// do stuff
}
// controller
def myService
def myControllerAction {
myService.myServiceMethod(params.foo, params.bar)
}
Exposing parameters from the controller to the service layer would break the layer-oriented approach Grails is trying to provide you; i.e. the "model" and "controller" components (of MVC) would be more tightly coupled.
I would also take a look at chaining actions as a way to pass the model information
http://www.grails.org/Controllers+-+Redirects
I'm sorry to ask such a basic question, but it's kind of fundamental for me. To better understand filters, I need to understand this notions. Although I'm on ASP.NET MVC for few months now and now are doing nice demos, I'm more familiar with Action method concept than action result.
What are:
Action Method?
Action Result?
How are they related?
Let's say I've this
public ViewResult ShowPerson(int id)
{
var friend = db.Persons.Where(p => P.PersonID == id).First();
return View(friend);
}
How those concepts apply to the above code?
Thanks for helping.
In your example ShowPerson is the action. Each action needs to return an action result (In your case it returns a view). So when a controller action method is invoked it does some processing and decides what view would be best adapted to represent the model.
There are many different action results that you might use. They all derive from ActionResult:
ViewResult - if you want to return a View
FileResult - if you want to download a file
JsonResult - if you want to serialize some model into JSON
ContentResult - if you want to return plain text
RedirectResult - if you want to redirect to some other action
HttpUnauthorizedResult - if you want to indicate that the user is not authorized to access this action
FooBarResult - a custom action result that you wrote
Answer by #Darin-dimitrov is very much upto the point. But I see explanation given on MSDN also very much helpful.
Action methods typically have a one-to-one mapping with user
interactions. Examples of user interactions include entering a URL
into the browser, clicking a link, and submitting a form. Each of
these user interactions causes a request to be sent to the server. In
each case, the URL of the request includes information that the MVC
framework uses to invoke an action method.
When a user enters a URL into the browser, the MVC application uses
routing rules that are defined in the Global.asax file to parse the
URL and to determine the path of the controller. The controller then
determines the appropriate action method to handle the request. By
default, the URL of a request is treated as a sub-path that includes
the controller name followed by the action name. For example, if a
user enters the URL http://contoso.com/MyWebSite/Products/Categories,
the sub-path is /Products/Categories. The default routing rule treats
"Products" as the prefix name of the controller, which must end with
"Controller" (such as ProductsController). It treats "Categories" as
the name of the action. Therefore, the routing rule invokes the
Categories method of the Products controller in order to process the
request. If the URL ends with /Products/Detail/5, the default routing
rule treats "Detail" as the name of the action, and the Detail method
of the Products controller is invoked to process the request. By
default, the value "5" in the URL will be passed to the Detail method
as a parameter.
Perhaps this is impossible, but I figured I would ask anyway. I'm working on an ASP.NET MVC application that uses jquery/AJAX extensively. One of the AJAX tasks that gets performed is a call to controller action that returns a URL to redirect the user to.
What I would like to do is to have the same controller context when making an AJAX call as I do on the current page. The reason for this is because the controller action called by AJAX makes use of the Url.Action() method and I need it to use the same route values as what is currently being used on the current page.
So for example, if a user is currently on: /Site/Search/Advanced/Widgets/Black and Blue/1/Descending, mapping to a route of Site/Search/Advanced/{objectType}/{query}/{pageNum}/{displayMethod}, with {objectType} defaulting to "Cars" (not "Widgets").
I would like a call to Url.Action("Advanced", "Search", new {query="Something else"}) to generate /Site/Search/Advanced/Widgets/Something else/1/Descending.
As it stands, the call will generate /Site/Search/Advanced/Cars/Something else, because the controller does not what context it is in.
My alternative is to specify the additional parameters directly in the Url.Action call, but that would require a lot more complexity with values coming in and out of jquery AJAX through various hidden fields, which would be a huge mess...
Any ideas?
Assuming that you on every ajax call want the route values you haven't specified to be the same as in the original non-ajax request, you could always make use of ViewContext.RouteData to add the extra parameters to the ajax call. When the ajax call is returned, you use the route data to add to any new links in the asynchronously loaded results.
Another way is to use the Session object to keep track of the last request, and change the values if new ones are sent.
On the other hand, I would like to question your goal (if this search scenario is your actual scenario): If I search for something, browse to page 4, and then enter a new search term, I don't expect to go to page 4 of the new search results - I expect the first page (although I do expect that my chosen sorting order is preserved...).