So I am a newbie grails developer, and was wondering how to properly use services per the MVCS design pattern. Right now in my service, I have a couple functions doing my application logic, and then I am referencing the service directly from my gsp. I read on a comment here that this is not good form. So right now I have
<g:set var="doc" bean="documentPartService"/> directly in my gsp.
So I am looking to change it, just like the comment states, by passing the information through the right channels.
One little hurdle I am coming across is passing information from my service to my controller to my gsp. For an example
<g:form name="inputForm" action="replace">
somecodehere...
<input value="Submit" type="submit">
</g:form>
then in my replace function in my controller
def replace(){
render documentPartService.replace(params)
}
then I have some logic in my service.
I have seen in some services I have looked at, they return the variable as a json (documentBody is a variable local to my service)
return documentBody as JSON
but I am a little puzzled on how to actually access this in my controller/view. I can't just
print documentBody in my controller, because it is only defined in my service. In the plugin services and controllers I was using as references, the controllers are 1 liners, just like I have, where the only thing they do is render servicefunction()
Can anyone shed some light on how I should properly design this?
When you post your form the action is replace - the replace action in your controller renders the output of your service back out as the output rather than returning a gsp bound to the replace controller definition.
In theory it should work as in the user will post - the post will return the action replace which will return that JSON response.
the alternative is
def replace(){
def myValue=documentPartService.replace(params)
render (view: 'replace', model: [myValue:myValue ])
}
then you could have a gsp page called replace which has ${myValue} defined in it which will be its results.
Also its probably a better idea to call your service with defined values passed via the controller to it:
def replace(String val1,String val2,String val3){
def myValue=documentPartService.replace(val1,val2,val3)
[myValue:myValue ]
}
UPDATE
It may seem much coming from me to be hinting the latter method considering you probably seen the first call i.e.
render documentPartService.replace(params)
calls similar to above methods within one of my plugins.. I guess if you took a look at the mailinglist plugin, you will notice with the help of Burt. The controllers/services are locked down to data types and exact expectations.
I can only tell you from experience that best practices are if they are to be defined functions that have no reason for expansion then stick with the latter method. In the case of for example ajaxdependancyselection using the render services output method, in some ways this helps keep it more backward/forward compatible. But actually thinking about it maybe those calls can be locked down. Will update the plugin soon
Related
Angular newb here, thoughts appreciated...
Say I want an input field to control the window title as you type. A field with a model binding and no associated controller acts on keypress, as intended. However, there has to be a bit more logic to it -- default value before any user input, also used if the input is blanked.
Adding a controller bound to enclosing elements gives a place for that logic, but the change-on-keypress behavior is gone. I'm sure it's possible to recreate it by hand or with ui, but since it's inherently there without the controller, I'm wondering if I'm missing the simple clean way.
Simple version, acts on keypress, but with no smarts:
<title ng-bind-template="{{windowTitle}}">Default Title (not seen)</title>
<input ng-model="windowTitle" type="text">
Putting controller bindings on the head (for the title) and a containing div (for the input), and setting a default $scope.windowTitle inside the controller function does use that default value, but it breaks the auto-update.
I know in real life you'd want a real model, but what I'm really trying to understand is these two ways angular appears to work. I haven't found anything specifically describing two different implicit input binding behaviors, but I haven't been through all the docs yet.
How should I be thinking about this?
Edit: It's not the window title or default value per se that I'm interested in. I'm trying to understand this:
When there's no controller on either the field or the title, typing in the field changes the window title immediately, on keypress. The title is directly linked to the field value, with no other angular hookup.
With controller bindings around the title and the field, typing in the field has no effect on the title.
What I've since realized (I think) is that ng-controller bindings create a new instance of the controller each time. Here's the non-working code I didn't show before:
<title ng-controller="TitleCtrl" ng-bind-template="{{windowTitle || 'Foo'}}">Foo</title>
...
<label ng-controller="TitleCtrl">
<input ng-model="windowTitle" type="text">
{{windowTitle}}
</label>
The value set by the model binding to the field is shown correctly within that instance of that controller, and updates on keypress, as before. But since those two controller instances are separate, the binding to the title works but the data it points to isn't bound to the field.
Isn't that right? The reason it works with no controllers is that that makes the value global, so the title binding sees the value set by the field binding.
So what's the canonical way to reference data from some other area? Create a service?
I realize that this is basic angular stuff, just getting started here, so thanks!
Edit 2
On reflection, I've come to seriously disrespect this whole question, even though I wrote it.
It's based on way-too-early poor understanding of the Angular application model. I had worked through only part of the official tutorials, and jumped ahead to removing all the js from a not big but not totally trivial existing app, and exploring what Angular could to in that context.
I got some very quick bang for the buck, getting several pieces of functionality working with very little code, and simple, clear markup, felt good. But I really had short-circuited internalizing the Angular way of thinking, and my quick and dirty no-architecture approach broke down when different parts of the page needed to coordinate with each other, as in this question.
I've postponed that project while I go back to tutorials and other learning. If other folks think this question should be deleted, I'd add my vote. Or maybe it's a useful on some level, ignorant though it is.
Well, there are multiple ways to achieve the behavior you want without using an explicit controller and model, you could:
<title ng-bind-template="{{windowTitle && windowTitle || 'default'}}"></title>
Or in a more simple way:
<title>{{windowTitle && windowTitle || 'default' }}</title>
In both cases, we're using the conditional expression:
(condition) && (answer if true) || (answer if false)
You should however strive to remove logic from the templates.
In my ApplicationController parent class I have an action method called dig which reads parameters via the params[] hash-like structure. I would like to have any view that builds a link to any controller via link_to helper function with the dig action to call the parent's action first. I'd like to then be able to determine either what that parameterized information represents (its type), or what created the link (the previous or originating view).
Any ideas on the best way to do this? Is there a way to pass an object via the link_to and then use its meta data? If so, would this break the rails paradigm?
If you're looking for what called what inside your code, Ruby's caller method is the basis for the stack dump that occurs when an exception occurs. You can tap into that and ask what the calling chain was at any point.
If you want to trace the incoming requests from the browser from an outside site, it becomes a lot more difficult because browsers don't like to reveal the last location any more. If the browser is being redirected around your own site you can use sessions or cookies to trace its movement.
I think that to have the originating link what you would need to do is something like this:
request.env['HTTP_REFERER']
This will get the URL where the action was originated, from there you can process the URL to get controller, action and id. Hope this helps!
So this seems like it should be simple. I'd like to set a public model property from javascript that's fired on the mouseover of an image.
So something like this:
Html:
...img src="<%=Model.AppDetails.Logo%>" onmouseover="showMenu(this);...
Javascript:
function showMenu(app) {
<%Model.CurrentId = app.id%> //app.id is of course undefined here
...
Or is a better approach to call a controller method to set it? If so what's the best approach? Ajax? Seems like a lot of heavy lifting for something so simple.
Appreciate the feedback.
Sharon
What exactly are you trying to do with Model.CurrentId? If you're trying to just send it back to the server when the page next sends information, use a hidden field or similar.
However, if you're trying to set a value on the server when the user mouses over an image, of course you need to use ajax or similar. How else is the server going to know what the client is doing.
If you want to use Model.CurrentId later in the same file, you will need to re-apply the template as well. Once the view is processed on the server, the client has no information from the template (the client doesn't see the <%...%> tags, those are replaced on the server before sending).
I can't imagine any scenario where you'd want to send information to the server on a mouseover unless you were going to also get information back (like an extended tooltip, or an image popup), so ajax is probably your best option.
I'm facing a strange problem in my project. My actions are getting old param values instead of the actual values which are in Request.Params. I created a HomeController.Echo(string text) action to illustrate it (see screenshot). When I call the action for the first time like "Home/Echo?text=aaa" everything works fine. When I call the same action second time with different text value ("Home/Echo/text=bbb"), I get the old "aaa" value again in my action "text" parameter. Strange think is that Request.Params contains the right "bbb" value.
I'm thinking if there's something I could break myself, but can't figure out anything. I'm serving controllers from IoC container, I overrided ControllerActionInvoker.InvokeActionMethodWithFilters method (to inject dependencies into filters from IoC) and I'm handling HttpApplication.AuthenticateRequest. Im'not working with params/binding anyhow in any of these...
screenshot
The problem was caused by some threading issues probably - I forgot to register controllers in my IoC container with per-request lifecycle (they were registered as singletons).
Have you debugged through the application to see where the value is getting switched out. A simple watch on the text variable (whatever you call it in the code) should yield where the variable gets changed. Without code to run through, I have no clue where it is happening.
I would say write a test, but there is still a possibility of UI interfering here. If you find where in the code it is changing, then write a test to confirm the bug and start whacking at it.
I suggest you to start commenting all the methods you overrode until you isolate the problem. In worst case you will get to the point where the ASP.NET MVC wizard left your project when you created it and where parameter binding definitely worked.
I am implementing a dashboard as a relative Rails newbie (more of an infrastructure guy). The dashboard will consist of multiple pages, each page of which will contain multiple charts/tables/etc. For modularity, I want it to be as easy as possible to add new charts or change views of the data.
Say one page has 5 different charts. I could have the controller do 5 separate data lookups, hold all the relevant data in instance variables, and render 5 partials, each of which touch subsets of the data. But it seems more modular to have one "index" controller action whose render has a bunch of divs, and for each div there is another controller action which does the data lookup and has an associated view partial in charge of managing the view of that data within the div.
So if I'm showing the website dashboard page which has two graphs, website/index would use website/graph1 and website/graph2 to look up the data for each and then _graph1.html.erb and _graph2.html.erb would use the controller data to fill out divs "graph1" and "graph2", etc.
Is this the right design, and if so, what's the easiest way to accomplish this? I have an approximation using remote_function with :action => "graph1" to fill out divs, but I'm not 100% happy with it. I suspect I'm missing something easier that Rails will do for me.
Version 1:
Simple method that I've actually used in production: iframes.
Most of the time you don't actually care if the page renders all at once and direct from the server, and indeed it's better for it to load staggered.
If you just drop an iframe src'd to the controller's show action, you have a very simple solution that doesn't require direct cross-controller interactions.
Pro:
dead easy
works with existing show actions etc
might even be faster, depending on savings w/ parallel vs sequential requests and memory load etc
Cons:
you can't always easily save the page together with whatever-it-is
iframes will break out of the host page's javascript namespace, so if they require that, you may need to give them their own minimalist layout; they also won't be able to affect the surrounding page outside their iframe
might be slower, depending on ping time etc
potential n+1 efficiency bug if you have many such modules on a page
Version 2:
Do the same thing using JS calls to replace a div with a partial, à la:
<div id="placeholder">
<%= update_page {|page| page['placeholder'].replace with some partial call here } %>
Same as above, except:
Pro:
doesn't lock it into an iframe, thus shares JS context etc
allows better handling of failure cases
Con:
requires JS and placeholder divs; a bit more complex
Version 3:
Call a whole bunch of partials. It gets complicated to do that once you're talking about things like dashboards where the individual modules have significant amounts of setup logic, however.
There are various ways to get around this by making those things into 'mixins' or the like, but IMO they're kinda kludgy.
ETA: The way to do it via mixins is to create what is essentially a library file that implements your module controllers' setup functions, include that wherever something that calls 'em is used, and call 'em.
However, this has drawbacks:
you have to know what top level controller actions will result in pages that include those modules (which you might not easily, if these are really widgety things that might appear all over, e.g. user preference dependent)
it doesn't really act as a full fledged controller
it still intermixes a lot of logic where your holding thing needs to know about the things it's holding
you can't easily have it be segregated into its own controller, 'cause it needs to be in a library-type file/mixin
It IS possible to call methods in one controller from another controller. However, it's a major pain in the ass, and a major kludge. The only time you should consider doing so is if a) they're both independently necessary controllers in their own rights, and b) it has to function entirely on the back end.
I've had to do this once - primarily because refactoring the reason for it was even MORE of a pain - and I promise you don't want to go there unless you have to.
Summary
The best method IMHO is the first if you have complex enough things that they require significant setup - a simple iframe which displays the module, passing a parameter to tell it to use an ultraminimalist layout (just CSS+JS headers) because it's not being displayed as its own page.
This allows you to keep the things totally independent, function more or less as if they were perfectly normal controllers of their own (other than the layout setting), preserve normal routes, etc.
If you DON'T need significant setup, then just use partials, and pass in whatever they need as a local variable. This will start to get fragile if you run into things like n+1 efficiency bugs, though...
why don't you give Apotomo a try, that's stateful widgets for Rails:
A tutorial how to build a simple dashboard
You could achieve this by using
render_output = render :action => "graph2"
But Me personally would probably wrap the code in either a shared helper or write you own "lib" under the lib directory to reuse the code with a shared template. Remember that unless you change your route.rb file any public method defined is accessible by
/controller/action/:id
Also remember to turn off the layout for the function :layout => nil (or specify at the top of the controller layout "graph", :except => ["graph2"]
Cheers
Christian
I'm not aware of any special Rails tricks for achieving this without using AJAX in the way you've outlined.
The simplest way to get the modularity you seek is to put those portions of controller code into separate methods (e.g. set_up_graph1_data, set_up_graph2_data, etc.), which you simply call from your index action to set up the variables for the view.
You can put these methods into ApplicationController if you want them available to multiple controllers.
As a side note, early on, Rails did used to have a feature called 'components' which would allow you to do exactly what you're asking for here, without having to use AJAX. From your view, you could just render another controller action, inline. However, this feature was removed for performance and design philosophy reasons.