Grails始めました
昨日の夜から今日の昼までにやったGrailsのtwitterでの作業ログを残しておく。
【Grails徹底入門】を探して四条(京都)を歩き回る。
【Grails徹底入門】を入手。川原町四条のマクドナルドでひたすら読みふけって3時間かけてざっと読了(プラグインのところは良く分かっていない)
ダイナミックメソッド、beforeDeleteだけじゃなくてafterもないかなぁ。削除ログを残す時に何か気持ち悪い。トランザクションかかるから結果は同じだろうけど。 #grails
posted at 21:12:41
帰宅&初めてのGrails!
古いマシンを引っ張り出してきて使用。Javaからインストール。
日付変わる。
ハマった。
理由: 何も知らずに c:\grails-app というディレクトリを作成し、その下にgrailsのアプリと作ろうとしたらコンパイルできない状態になった。
grails create-app すると grails-app というディレクトリができるがその名前と重複してるのが悪いのだろうか? 新しく他の名前にしたところすんなり動いた。
やっと、HelloWorldできた。どうやらアプリ用に区切ったディレクトリ名がgrails-appにしてたのが問題っぽい。create-appで同じ名前のgrails-appというのが自動生成されてるのでどっちかわからなかったのかな?
posted at 00:38:17
深夜のため愚痴が増える。
最終的に generate-all しちゃったほうがイイかなという結論に。
理由は Web Flow の使用は複雑な遷移やflowスコープを利用したデータ登録時だけでいいと思うから。
それ以外は Web Flow を使わないほうが楽。
続き。マシンが絶不調。Web Flow の動きと View の関連が分からず終了。
代わりにAuto Reloadingなど内部の仕組みをちょっと調べる。
自動リロード(Auto Reloading)については以下のURLを参照
Grails - Japanese Auto Reloading
grailsWebRequest=org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter
posted at 02:15:54
reloadFilter=org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter
posted at 02:16:03
起床。ちょっとニュースを読んだ後、Grails再挑戦。
Web Flowの動きがやっと掴める。
徐々に分かってきた。Web Flowに入るには redirect(action: "xxxFlowのxxx部分") Flow毎に階層が分けられて、views/controller/flow/state.gsp になる 全部Flowを使う必要なく遷移が複雑になるところに使うと良い
posted at 10:16:34
データ登録系はWeb Flowを使うのかな。取ってきた値をbindDataして突っ込むと。validateも簡単。あとはvalidateが柔軟に使えるかどうか、だ。
posted at 11:11:25
Constraintsをカスタマイズしたくなる。Pluginがあったのでインストール。
エラーが出力される順番が変なことに気付く。
How can I change the order of "g:renderErrors"? I think default order of "g:renderErrors" looks a little strange.. #grails
posted at 11:45:15
昼食後、午前中に悩んだ 入力→確認→入力 に戻ったときに入力された値が入らない問題が一瞬で解決される。
とりあえず終わり。
作ったサンプル
一覧、会員登録(入力→確認→完了)
■ドメインクラス domain
Member.groovy
class Member implements Serializable { String name String password String passwordConfirm String email String zipcode Date birthDate static transients = ["passwordConfirm"] static constraints = { name(blank:false) password(blank:false) passwordConfirm(validator : { val, obj -> val == obj?.password }) email(blank:false, email:true) zipcode(zipcode:true) birthDate() } }
■コントローラークラス controllers
MemberController.groovy
class MemberController { def index = { redirect(action:"list") } def list = { [members : Member.list()] } def registrationFlow = { start { action { flow.member = new Member() } on("success").to "input" } input { on("doConfirm"){ bindData(flow.member, params) flow.member.validate() ? success() : error() }.to "confirm" } confirm { on("back").to "input" on("doRegistration"){ flow.member.save() }.to "registration" } registration() } }
■ユーティリティークラス utils
郵便番号のValidator(Constraints)に使用
※grails-custom-constraintsをインストールする必要あり
ZipcodeConstraint.groovy
class ZipcodeConstraint { def validate = { val -> return val ==~ /^\d{3}[- .]?\d{4}$/ } }
■ビュー(※一覧(list)はgenerate-viewした内容とほぼ同一の為割愛)
views/member/registration/input.gsp
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta name="layout" content="main" /> <title>会員登録</title> </head> <body> <div class="nav"> <span class="menuButton"><a class="home" href="${resource(dir:'')}">Home</a></span> </div> <div class="body"> <h1>会員登録</h1> <g:if test="${flash.message}"> <div class="message">${flash.message}</div> </g:if> <g:hasErrors bean="${member}"> <div class="errors"> <g:renderErrors bean="${member}" as="list" /> </div> </g:hasErrors> <g:form action="registration" method="post"> <div class="dialog"> <table> <tbody> <tr class="prop"> <td valign="top" class="name"> <label for="name">名前:</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'name','errors')}"> <input type="text" id="name" name="name" value="${fieldValue(bean:member,field:'name')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"> <label for="password">パスワード:</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'password','errors')}"> <input type="text" id="password" name="password" value="${fieldValue(bean:member,field:'password')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"> <label for="passwordConfirm">パスワード(確認):</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'passwordConfirm','errors')}"> <input type="text" id="passwordConfirm" name="passwordConfirm" value="${fieldValue(bean:member,field:'passwordConfirm')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"> <label for="email">メールアドレス:</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'email','errors')}"> <input type="text" id="email" name="email" value="${fieldValue(bean:member,field:'email')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"> <label for="email">郵便番号:</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'zipcode','errors')}"> <input type="text" id="zipcode" name="zipcode" value="${fieldValue(bean:member,field:'zipcode')}"/> </td> </tr> <tr class="prop"> <td valign="top" class="name"> <label for="birthDate">生年月日:</label> </td> <td valign="top" class="value ${hasErrors(bean:member,field:'birthDate','errors')}"> <g:datePicker name="birthDate" value="${member?.birthDate}" precision="day" ></g:datePicker> </td> </tr> </tbody> </table> </div> <div class="buttons"> <span class="button"><g:submitButton name="doConfirm" value="確認" class="save"/></span> </div> </g:form> </div> </body> </html>
views/member/registration/confirm.gsp
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta name="layout" content="main" /> <title>会員登録 - 入力確認 -</title> </head> <body> <div class="nav"> <span class="menuButton"><a class="home" href="${resource(dir:'')}">Home</a></span> </div> <div class="body"> <h1></h1> <g:if test="${flash.message}"> <div class="message">${flash.message}</div> </g:if> <div class="dialog"> <table> <tbody> <tr class="prop"> <td valign="top" class="name">名前:</td> <td valign="top" class="value">${fieldValue(bean:member, field:'name')}</td> </tr> <tr class="prop"> <td valign="top" class="name">パスワード:</td> <td valign="top" class="value">${fieldValue(bean:member, field:'password')}</td> </tr> <tr class="prop"> <td valign="top" class="name">メールアドレス:</td> <td valign="top" class="value">${fieldValue(bean:member, field:'email')}</td> </tr> <tr class="prop"> <td valign="top" class="name">郵便番号:</td> <td valign="top" class="value">${fieldValue(bean:member, field:'zipcode')}</td> </tr> <tr class="prop"> <td valign="top" class="name">生年月日:</td> <td valign="top" class="value">${fieldValue(bean:member, field:'birthDate')}</td> </tr> </tbody> </table> </div> <div class="buttons"> <g:form action="registration" method="post"> <span class="button"><g:submitButton name="back" value="戻る" /></span> <span class="button"><g:submitButton name="doRegistration" value="登録" class="save" /></span> </g:form> </div> </div> </body> </html>
views/member/registration/registration.gsp
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta name="layout" content="main" /> <title>会員登録完了</title> </head> <body> <div class="nav"> <span class="menuButton"><a class="home" href="${resource(dir:'')}">Home</a></span> <span class="menuButton"><g:link class="list" action="list">一覧</g:link></span> </div> <div class="body"> <h1>会員登録が完了しました</h1> <g:if test="${flash.message}"> <div class="message">${flash.message}</div> </g:if> </body> </html>