[Grails]ドメイン名と異なるコントローラでscaffolding

#概要
例えば`Hoge`というドメインがある場合、普通であれば`HogeController`というコントローラを用意して、それをHogeドメインのscaffolding用コントローラにします。
ところが、ドメイン名とscaffold用のコントローラ名を別のものにしたい！という要望がよく出てきます（自分の場合）

そういう場合、別名のコントローラのプロパティに、このコントローラは`Hogeドメイン`のscaffoldようだよという宣言をしてあげることで対応できます。
例えば`TestController`というコントローラで`Hoge`ドメインを扱いたい場合は以下のようにします。

```groovy:TestController.groovy
class TestController {
    static scaffold = Hoge
}
```

コレだけでOK!!
/test/にアクセスすれば、ちゃんとHogeドメインの一覧が表示されます。

#問題点
じつはこの状態だと、データの閲覧はできますが新規登録、更新、削除ができません。
というのも、フォームの送信先のコントローラ名が、ドメイン名になってしまうためです。

#解決方法
コレを回避するために、テンプレートを修正します。

##テンプレートのインストール
まずは以下のコマンドを実行してテンプレートを編集できるようにします。

`grails install-templates`

##create.gspの修正
###formタグの修正
`src/templates/scaffolding/create.gsp`のformタグを以下のように編集します。

修正前

```html
<g:form url="[resource:${propertyName}, action:'save']" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>

```
修正後

```html
<g:form url="[action:'save']" method="POST" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
```


##edit.gspの修正
###フォームタグの修正
`src/templates/scaffolding/edit.gsp`のformタグを以下のように修正します。

修正前

```html
<g:form url="[resource:${propertyName}, action:'update']" method="PUT" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
```
修正後

```html
<g:form url="[action:'update']" method="PUT" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
```

###hiddenフィールドの追加
さらにhiddenFieldをg:actionSubmitタグの上に追記します。

```html:src/templates/scaffolding/edit.gsp
<!--g:hiddenFieldを追記-->
<g:hiddenField name="id" value="\${${propertyName}?.id}" />
<g:actionSubmit class="save" action="update" value="\${message(code: 'default.button.update.label', default: 'Update')}" />
```

##show.gspの修正
次に、`src/templates/scaffolding/show.gsp`のフォームタグの部分を以下のように修正します。

修正前

```html:src/templates/scaffolding/show.gsp
<g:form url="[resource:${propertyName}, action:'delete']" method="DELETE">
<fieldset class="buttons">
  <g:link class="edit" action="edit" resource="\${${propertyName}}">
    <g:message code="default.button.edit.label" default="Edit" />
  </g:link>
  <g:actionSubmit class="delete" action="delete" value="\${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('\${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form> 
```

修正後

```html:src/templates/scaffolding/show.gsp
<g:form url="[action:'delete']" method="DELETE">
<fieldset class="buttons">
  <g:link class="edit" action="edit" params="[id:${propertyName}.id]">
    <g:message code="default.button.edit.label" default="Edit" />
  </g:link>
  <g:hiddenField name="id" value="\${${propertyName}?.id}" />
  <g:actionSubmit class="delete" action="delete" value="\${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('\${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form>

```
**resource="\${${propertyName}}**を削除します。
さらに、linkタグのパラメータの修正と、edit.gsp同様にhiddenFieldを追記しています。
コレでひとまず動作します。

#Controller.groovyの修正
処理自体はテンプレート通りで特に問題ありませんが、データベースを更新したあとのリダイレクトの宛先のコントローラ名が、ドメイン名になってしまっているので、その部分を修正します。
該当ファイルは、テンプレートである`/src/templates/scaffolding/Controller.groovy`です。
**saveメソッドとupdateメソッド両方で同じように修正する必要があります。**
修正前

```groovy:src/templates/scaffolding/Controller.groovy
request.withFormat {
    form multipartForm {
        flash.message = message(code: 'default.updated.message', args: [message(code: '${className}.label', default: '${className}'), ${propertyName}.id])
        redirect ${propertyName}
    }
    '*'{ respond ${propertyName}, [status: OK] }
}
```

修正後

```groovy:src/templates/scaffolding/Controller.groovy
request.withFormat {
    form multipartForm {
        flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
        redirect action: 'show', id:${propertyName}.id
    }
    '*' { respond ${propertyName}, [status: CREATED] }
}
```
redirectの部分を修正しています。
コレで、モデルの更新後のリダイレクトが正常に動作するようになります。

#まとめ
やることといえば、基本的にはテンプレートをちょこっと修正するだけです。
テンプレートを元に戻したい場合はVCSから戻すのもいいし、サイトinstall-templateを実行してもOKです。
また、やっぱりドメイン名と同名のコントローラでscaffoldしたい！となった場合、今回の修正をしていても問題なくscaffoldは動作します。