参考:
http://grails.org/plugin/twitter-bootstrap
http://getbootstrap.com/
http://foodforcoding.com/2013/05/25/grails-with-twitter-bootstrap/
直接css等をダウンロードして利用する方法もあるけど、今回はプラグインを利用してみる。
どうしても手動でやりたい!という場合はココを参照
プロジェクトの作成
とりあえず適当なディレクトリにテスト用のプロジェクトを作成。
今回は bootstraptest というプロジェクト名にした。
grails create-app bootstraptest
プラグインのインストール
plugins {
// 以下を追記
runtime ':twitter-bootstrap:3.0.3'
}
Grailsのインタラクティブモードであれば、いったん抜ける。
そしてgrails clean
、grails compile
、grails run-app
を順番に実行。
Grailsのインタラクティブモードやクラスパスの設定など、本来は動的に行われるはずだけど、よくリロードが上手く動かなかったりするので、プラグインのインストール時や、開発時に動作が怪しいと思った際には上記の インタラクティブモードを抜ける -> clean -> compile -> run-appを実行した方がスッキリ。
実際に試してみる
とりあえずテスト用のコントローラとビューを作成
grails> create-controller hello
| Created file grails-app/controllers/bootstraptest/HelloController.groovy
| Created file grails-app/views/hello
| Created file test/unit/bootstraptest/HelloControllerSpec.groovy
で、実際のビューファイルは作成してくれないので、手動で grails-app/views/hello/index.gsp を作成する。
そのindex.gspを以下のようにする。
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta name="layout" content="main"/>
<title></title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
そして、 grails-app/views/layouts/main.gsp を以下のようにする。
<!DOCTYPE html>
<html lang="en">
<head>
<r:require modules="bootstrap"/>
<g:layoutTitle/>
<r:layoutResources/>
</head>
<body>
<g:layoutBody/>
<r:layoutResources/>
</body>
</html>
ちなみにこのmain.gspがいわゆるテンプレートになっていて、GrailsではこれをSitemeshを利用して実現しています。
ドキュメントはここ
基本的にこれで完了。
実際にhttp://localhost:8080/bootstraptest/hello/indexにアクセスするとBootstrapが適用されているのが確認できるはず。
もう少し具体的に
http://getbootstrap.com/examples/navbar/を参考にしてみる。
- web-app/css/navbar.css を作成し、以下のようにする。
body {
padding-top: 20px;
padding-bottom: 20px;
}
.navbar {
margin-bottom: 20px;
}
- grails-app/views/layouts/main.gsp を以下のように修正する。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'navbar.css')}" type="text/css">
<r:require modules="bootstrap"/>
<g:layoutTitle/>
<r:layoutResources/>
</head>
<body>
<div class="container">
<!-- Static navbar -->
<div class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li class="dropdown-header">Nav header</li>
<li><a href="#">Separated link</a></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="active"><a href="./">Default</a></li>
<li><a href="../navbar-static-top/">Static top</a></li>
<li><a href="../navbar-fixed-top/">Fixed top</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
<g:layoutBody/>
</div> <!-- /container -->
<r:layoutResources/>
</body>
</html>
これでhttp://localhost:8080/bootstraptest/hello/indexに再度アクセスするとイケてる画面が表示される。
上手く反映されなかったりする場合は、 インタラクティブモードを抜ける -> clean -> compile -> run-app の黄金パターンを実行する。
scaffoldも試してみる
適当にドメインを作成・・・今回はBookというドメインを生成
grails> create-domain-class Book
| Created file grails-app/domain/bootstraptest/Book.groovy
| Created file test/unit/bootstraptest/BookSpec.groovy
grails>
出来上がったBook.groovyに適当にプロパティを追加
package bootstraptest
class Book {
String name
Boolean enable = false
Integer price
static constraints = {
}
}
scaffold用のコントローラとビューを生成
grails> generate-all bootstraptest.Book
| Finished generation for domain class bootstraptest.Book
grails>
これでhttp://localhost:8080/bootstraptest/book/indexにアクセスすれば!
...なんがダサい・・・
まぁこれは当然で、そもそもデフォルトのscaffoldはBootstrapなんて知らないよ!という。
なので、scaffoldが利用しているデフォルトのデザインを変更してあげます。
scaffoldのデザインを変更
install-templates
コマンドを使ってデフォルトのデザインを編集できるようにします。
grails> install-templates
| Templates installed successfully
上記のコマンドを実行すれば、Grailsが自動生成するデフォルトのデザインが編集できるようになります。
src/templates/ がそれで、今回はscaffodingのテンプレートをいじりたいから src/templates/scafflding が対象。
デフォルトで生成されたものは当然今までscaffoldで利用されていたものなので、もちろんこのままではダメ。
example grails projectからプロジェクト全体をzipで落としてきて、 src/templates/scafflding の中の create.gsp、 edit.gsp、 list.gsp、 show.gspの4つを上書きする。
その際に注意点が3つ。
1.今回はmain.gspを編集してテンプレートと利用しているため。<meta name="layout" content="bootstrap">
を<meta name="layout" content="main">
に変更する必要がある。
2.<f:all bean="${propertyName}"/>
を<g:render template="form"/>
に変更する。(ダウンロードしてきた create.gsp と edit.gsp)。
これは、ダウンロードしたサンプルがFields Pluginを利用しているため。
今回このプラグインは利用しないので、書き換える必要がある。
(メモ:fieldsプラグインを使えば細かくフォームデザインをカスタマイズできるのかも?参考サイト)
3.テンプレートの編集は、Grailsを再起動しないと反映されない。
つぎに、BookControllerを動的scaffoldにしておく
package bootstraptest
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
@Transactional(readOnly = true)
class BookController {
static scaffold = Book
}
これでやっと完成!http://localhost:8080/bootstraptest/book/listにアクセスすれば確認できます。
もちろんこのままだと・・・という人も居ると思うので、そういう人は適宜自分でテンプレートを修正すればOK.
実際に運用していかないとどういう問題が出るか分からないけど、scaffold用のSitemeshとその他のページのSitemeshは分けておいた方が無難かも・・・?
なお、今回はテンプレートの Controller.groovy を編集していないので、静的scaffoldを利用する際には、お空うこちらも修正しないといけないかも?