Skip to content

Commit

Permalink
update to work with GSON plugin style controllers
Browse files Browse the repository at this point in the history
now have an alternate ng-resource setup that maps to Grails resource style URL mappings
  • Loading branch information
robfletcher committed Apr 15, 2013
1 parent 6ec32c0 commit 7af0ab3
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 232 deletions.
11 changes: 10 additions & 1 deletion grails-app/conf/AngularScaffoldingResources.groovy
Expand Up @@ -14,8 +14,17 @@ modules = {

'angular-scaffolding' {
dependsOn 'jquery', 'angular-resource'
resource id: 'js', url: [plugin: 'angular-scaffolding', dir: 'js', file: 'grails-default.js']
resource id: 'js', url: [plugin: 'angular-scaffolding', dir: 'js', file: 'scaffolding.js']
resource id: 'css', url: [plugin: 'angular-scaffolding', dir: 'css', file: 'scaffolding.css']
}

'angular-grails-default' {
dependsOn 'angular-scaffolding'
resource id: 'js', url: [plugin: 'angular-scaffolding', dir: 'js', file: 'grails-default.js']
}

'angular-grails-resource' {
dependsOn 'angular-scaffolding'
resource id: 'js', url: [plugin: 'angular-scaffolding', dir: 'js', file: 'grails-resource.js']
}
}
3 changes: 2 additions & 1 deletion test/apps/grails-ng/grails-app/conf/BuildConfig.groovy
Expand Up @@ -24,7 +24,8 @@ grails.project.dependency.resolution = {
build ":tomcat:$grailsVersion"

compile ':cloud-foundry:1.2.3',
':cache-headers:1.1.5'
':cache-headers:1.1.5',
':gson:1.1.4'

runtime ":hibernate:$grailsVersion",
':resources:1.2.RC2',
Expand Down
4 changes: 4 additions & 0 deletions test/apps/grails-ng/grails-app/conf/UrlMappings.groovy
@@ -1,6 +1,10 @@
class UrlMappings {

static mappings = {
"/album/index"(controller: "album", action: "index")
"/album"(controller: "album", action: "list")
"/album/$id?"(resource: "album")

"/$controller/$action?/$id?"{
constraints {
// apply constraints here
Expand Down
@@ -1,112 +1,154 @@
package grails.plugin.angular.test

import grails.plugin.gson.converters.GSON
import org.springframework.dao.DataIntegrityViolationException
import grails.converters.JSON
import static javax.servlet.http.HttpServletResponse.*
import static org.codehaus.groovy.grails.web.servlet.HttpHeaders.*
import static grails.plugin.gson.http.HttpConstants.*

class AlbumController {

static final int SC_UNPROCESSABLE_ENTITY = 422

static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

def index() { }

def list() {
cache false
params.max = Math.min(params.max ? params.int('max') : 10, 100)
response.setIntHeader('X-Pagination-Total', Album.count())
render Album.list(params) as JSON
}

def save() {
def albumInstance = new Album(request.JSON)
def responseJson = [:]
if (albumInstance.save(flush: true)) {
response.status = SC_CREATED
responseJson.id = albumInstance.id
responseJson.message = message(code: 'default.created.message', args: [message(code: 'album.label', default: 'Album'), albumInstance.id])
} else {
response.status = SC_UNPROCESSABLE_ENTITY
responseJson.errors = albumInstance.errors.fieldErrors.collectEntries {
[(it.field): message(error: it)]
}
}
cache false
render responseJson as JSON
}

def get() {
def albumInstance = Album.get(params.id)
if (albumInstance) {
cache false
render albumInstance as JSON
} else {
notFound params.id
def index() { }

def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
response.addIntHeader X_PAGINATION_TOTAL, Album.count()
render Album.list(params) as GSON
}

def save() {
if (!requestIsJson()) {
respondNotAcceptable()
return
}

def albumInstance = new Album(request.GSON)
if (albumInstance.save(flush: true)) {
respondCreated albumInstance
} else {
respondUnprocessableEntity albumInstance
}
}

def show(long id) {
def albumInstance = Album.get(id)
if (albumInstance) {
respondFound albumInstance
} else {
respondNotFound id
}
}

def update(long id) {
if (!requestIsJson()) {
respondNotAcceptable()
return
}

def albumInstance = Album.get(id)
if (!albumInstance) {
respondNotFound id
return
}

if (params.version != null) {
if (albumInstance.version > params.long('version')) {
respondConflict(albumInstance)
return
}
}
}

def update() {
println request.JSON
def albumInstance = Album.get(params.id)
if (!albumInstance) {
notFound params.id
return
}

def responseJson = [:]

if (request.JSON.version != null) {
if (albumInstance.version > request.JSON.version) {
response.status = SC_CONFLICT
responseJson.message = message(code: 'default.optimistic.locking.failure',
args: [message(code: 'album.label', default: 'Album')],
default: 'Another user has updated this Album while you were editing')
cache false
render responseJson as JSON
return
}
}

albumInstance.properties = request.JSON

if (albumInstance.save(flush: true)) {
response.status = SC_OK
responseJson.id = albumInstance.id
responseJson.message = message(code: 'default.updated.message', args: [message(code: 'album.label', default: 'Album'), albumInstance.id])
} else {
response.status = SC_UNPROCESSABLE_ENTITY
responseJson.errors = albumInstance.errors.fieldErrors.collectEntries {
[(it.field): message(error: it)]
}
}

cache false
render responseJson as JSON
}

def delete() {
def albumInstance = Album.get(params.id)
if (!albumInstance) {
notFound params.id
return
}

def responseJson = [:]
try {
albumInstance.delete(flush: true)
responseJson.message = message(code: 'default.deleted.message', args: [message(code: 'album.label', default: 'Album'), params.id])
} catch (DataIntegrityViolationException e) {
response.status = SC_CONFLICT
responseJson.message = message(code: 'default.not.deleted.message', args: [message(code: 'album.label', default: 'Album'), params.id])
}
cache false
render responseJson as JSON
}

private void notFound(id) {
response.status = SC_NOT_FOUND
def responseJson = [message: message(code: 'default.not.found.message', args: [message(code: 'album.label', default: 'Album'), params.id])]
render responseJson as JSON
}

albumInstance.properties = request.GSON

if (albumInstance.save(flush: true)) {
respondUpdated albumInstance
} else {
respondUnprocessableEntity albumInstance
}
}

def delete(long id) {
def albumInstance = Album.get(id)
if (!albumInstance) {
respondNotFound id
return
}

try {
albumInstance.delete(flush: true)
respondDeleted id
} catch (DataIntegrityViolationException e) {
respondNotDeleted id
}
}

private boolean requestIsJson() {
GSON.isJson(request)
}

private void respondFound(Album albumInstance) {
response.status = SC_OK
render albumInstance as GSON
}

private void respondUpdated(Album albumInstance) {
response.status = SC_OK
render albumInstance as GSON
}

private void respondDeleted(id) {
def responseBody = [:]
responseBody.message = message(code: 'default.deleted.message', args: [message(code: 'album.label', default: 'Album'), id])
response.status = SC_OK
render responseBody as GSON
}

private void respondCreated(Album albumInstance) {
response.status = SC_CREATED
response.addHeader LOCATION, createLink(action: 'show', id: albumInstance.id)
render albumInstance as GSON
}

private void respondNotFound(id) {
def responseBody = [:]
responseBody.message = message(code: 'default.not.found.message', args: [message(code: 'album.label', default: 'Album'), id])
response.status = SC_NOT_FOUND
render responseBody as GSON
}

private void respondNotAcceptable() {
response.status = SC_NOT_ACCEPTABLE
response.contentLength = 0
response.outputStream.flush()
response.outputStream.close()
}

private void respondConflict(Album albumInstance) {
albumInstance.errors.rejectValue('version', 'default.optimistic.locking.failure',
[message(code: 'album.label', default: 'Album')] as Object[],
'Another user has updated this Album while you were editing')
def responseBody = [:]
responseBody.errors = albumInstance.errors.allErrors.collect {
message(error: it)
}
response.status = SC_CONFLICT
render responseBody as GSON
}

private void respondUnprocessableEntity(Album albumInstance) {
def responseBody = [:]
responseBody.errors = albumInstance.errors.allErrors.collect {
message(error: it)
}
response.status = SC_UNPROCESSABLE_ENTITY
render responseBody as GSON
}

private void respondNotDeleted(id) {
def responseBody = [:]
responseBody.message = message(code: 'default.not.deleted.message', args: [message(code: 'album.label', default: 'Album'), id])
response.status = SC_INTERNAL_SERVER_ERROR
render responseBody as GSON
}

}
2 changes: 1 addition & 1 deletion test/apps/grails-ng/grails-app/views/album/index.gsp
Expand Up @@ -6,7 +6,7 @@
<meta name="layout" content="ng-app">
<g:set var="entityName" value="${message(code: 'album.label', default: 'Album')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
<r:require module="angular-scaffolding"/>
<r:require module="angular-grails-resource"/>
</head>
<body data-ng-app="scaffolding">
<div class="subnav">
Expand Down
2 changes: 2 additions & 0 deletions test/apps/grails-ng/grails-app/views/layouts/ng-app.gsp
Expand Up @@ -22,6 +22,8 @@
<r:layoutResources />
</head>
<body data-ng-app="${pageProperty(name: 'body.data-ng-app')}"
data-root-url="${createLink(uri: '/')}"
data-controller-name="${controllerName}"
data-base-url="${pageProperty(name: 'body.data-base-url', default: createLink(action: 'index').replaceAll(/index$/, ''))}"
data-template-url="${pageProperty(name: 'body.data-template-url', default: createLink(uri: "/ng-templates/$controllerName"))}"
data-common-template-url="${pageProperty(name: 'body.data-common-template-url', default: createLink(uri: '/ng-templates'))}">
Expand Down

0 comments on commit 7af0ab3

Please sign in to comment.