#Resource is creating controller that shadows my own controller - grails

To render JSON+HAL I've added #Resource anotation to my domain:
#Resource(uri = "/rest/book", formats=['hal'])
class Book {
String title
String author
}
The problem is that I already have BookController (no scaffolding) and creating ling via gsp tag (<g:createLink controller='book' />) always creates link to /rest/book not to specyfic action in controller (i.e. /book/index). What is also worth knowing when I type localhost:8080/book/index it is showing JSON response not gsp page.
The #Resource somehow cover the book controller and I don't know how to keep both of them working.
PS I'm using Grails 2.4.4

Use namespaces for your controller.
class BookController {
static namespace = 'namespaceOne'
// …
}
and then use the namespace to generate links to your BookController.
<g:link controller="book" namespace="namespaceOne">Click me</g:link>

Related

PageRenderer in Controller

Can we implement PageRender in controller (grails 3.2.8)? I tried in a service and it worked perfectly as expected.
But when I tried in a controller, I am not getting the expected results.
Controller:
class TestcontrollerController {
def RenderService
def gsp= "grails"
PageRenderer groovyPageRenderer
def index(String gsp) {
render creategsp()
}
def creategsp() {
groovyPageRenderer.render view: '/email/confirm', model: [gsp: findgsp()]
}
def findgsp() {
'<g:select from="${18..65}" value="${age}" />'
}
}
index.gsp:
<g:render template="/test/samplePage" />
samplePage.gsp:
<g:render template="/email/welcome" />
_display.gsp:
Hi ,{username} <br>
PageRenderer is not rendering any of the custom tags or grails tags.
Any suggestions?
Yes this is completely possible. Just define it at the top of your controller:
PageRenderer groovyPageRenderer
Note that you need to strongly type this, and not just "def" it.
Then when you use it, it will render pages to strings:
String renderViewResult = groovyPageRenderer.render(view: "/myViewName", model: renderModel)
If you update your question with more details like what you did, and what isn't working, possibly someone can help you more, but big picture: yep, it works!

How can I connect GSP Template Engines in a Controller with my Domain in Grails?

I did this tutorial to use the GSP Template Engine in a Controller to generate a view. Now I want to access to my database inside the html that I have in my controller, but I don't find the good way to do it. I want to access to my column name and template that I have in my domain.
I need to do it of this way, I know that I can do the same with the gsp file.
Controller:
class SendEmailController {
def groovyPagesTemplateEngine
def emailTemplate = {
def templateText = '''\
<html>
<body>
<h1 align="center">Hello</h1>
<p align="center">This is my text</p>
</body>
</html>
'''
def output = new StringWriter()
groovyPagesTemplateEngine.createTemplate(templateText, 'sample').make([show: true]).writeTo(output)
render output.toString()
}
}
DOMAIN
class SendEmail {
String name
String template
static constraints = {
}
}
You can retrieve a domain object in your controller by calling get() (passing in the id of the record you want to retrieve from the database) on the domain object class.
def emailTemplate = SendEmail.get(id).template
There are some other retrieval methods as well. Look at the GORM documentation for more information: https://grails.github.io/grails-doc/latest/guide/GORM.html.

Grails - URL mapping/default action and flow

Question -
I've noticed that some applications I test with have calls to another view/controller from an action submit, but when that page is rendered, instead of seeing:
$controller/$page
I see:
$controller/index
Is this an issue with the URL mapping configuration? Default action? Just curious, because it just appears to be the URI mapping to a default instead of the actual action.
view code:
<table>
..
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
..
</table
controller:
def stats() {
def teamId = Team.get(params.id)
def allPlayers = Player.withCriteria {
eq('team', teamId)
and {
eq('isActive', true)
}
}
[allPlayers:allPlayers, teamId:params.id]
}
UrlMapping:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
}
Edit
I actually figured out what it is. Which makes me even more confused.
The grails actionSubmit has an action tied to it. That form was just a normal form, without call:
<g:form>
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
<g:actionSubmit class="schedule" action="schedule" value="View Schedule"/>
<g:form>
So by default, the form redirects the action to $controller/index. If you add an action call in the g:form tag, those two buttons will direct to the correct page, but the URI will now be $controller/$g:form_action.
I guess I don't get the point of the actionSubmit's action if the g:form is needed as a wrapper.
Yes, index is the default action for all controllers. So if you do not specify one, that is the page you will land on for the controller.
It is discussed in further detail on their website. Namely, the rules are:
If only one action is present the default URI for a controller maps to
that action.
If you define an index action which is the action that
handles requests when no action is specified in the URI /book
Alternatively you can set it explicitly with the defaultAction property:
static defaultAction = "list"

Where to put controller-wide accessible objects

I would like give access to the (currently logged-in) user object to all controllers, and views, in my application. For example, I want to put the users name in my "sidebar" partial, but don't know how to access the user object since that is stored in an other controller. Thanks in advance.
You could use the Html.Action helper method. You could define a view model which will contain all the necessary information you would like to show about the currently logged in user (like his username for example) and then have a controller action which will use the User property of the controller to populate this view model and pass it to a corresponding partial view. Then inside your master page you would include this information using the Html.Action helper:
<div id="sidebar">
#Html.Action("Index", "Users")
</div>
which will invoke the Index action of the UsersController:
public class UsersController
{
public ActionResult Index()
{
UserViewModel model = ...
return PartialView(model);
}
}

Grails pattern to reuse template on error

I have a gsp template, where the data for create view is passed through the controller.
def create = {
def bookInstance = new Book()
bookInstance .properties = params
def map = getDefaultValues()
render(template: "create", model: [bookInstance : bookInstance ,
title: map.title,
somelist: somelist
....])
the gsp template
<g:select optionKey="id" from="${somelist}" name="somelist.id" value="${bookInstance ?.somelist?.id}" noSelection="['null': '']"></g:select>
now, in the save method, if there is an error, it returns currently populated and validated instance (default scaffold implementation)
render(template: "create", model: [bookInstance : bookInstance ])
But the fields in the gsp (error page rendered from save action) is empty. I could see the reason as it looks the value in "${somelist}" , but it is not used in save method. Do i just need to check for null in the gsp and use whichever map is available, or any better method (passing all the map in the save method is not an option) ..
thanks in advance..
I figured it out.. I have to pass the same map as was in the create closure .. the reason why we were passing the maps in create is because we wanted to override the default list.. the populated values in bookInstance is only used to preserve the user selection, but not all the values..

Resources