Grails始めました


昨日の夜から今日の昼までにやったGrailstwitterでの作業ログを残しておく。



Grails徹底入門】を探して四条(京都)を歩き回る。

京都って大きい本屋少ないね。大阪行こうかな。


posted at 17:24:01



Grails徹底入門】を入手。川原町四条のマクドナルドでひたすら読みふけって3時間かけてざっと読了(プラグインのところは良く分かっていない)

Grailsでweb flow使う場合、1ステートに対して1gspじゃないといけないの? #grails


posted at 20:28:11


ダイナミックメソッド、beforeDeleteだけじゃなくてafterもないかなぁ。削除ログを残す時に何か気持ち悪い。トランザクションかかるから結果は同じだろうけど。 #grails


posted at 21:12:41


Grails徹底入門読み終えた。3時間かかったけど面白かった。帰って試してみようっと。


posted at 21:15:46



帰宅&初めてのGrails

あら、帰ったらこんな時間・・・。


posted at 23:19:07


どこまでできるかわからないけど Grails はじめよう。


posted at 23:27:39


とりあえずダウンロードから。 http://www.grails.org/Download


posted at 23:29:08


ああ、結構かかるのね。。。


posted at 23:30:25



古いマシンを引っ張り出してきて使用。Javaからインストール。

なんてこった!Javaが入ってない!!


posted at 23:31:57


JDKダウンロード中・・・...


posted at 23:37:11


あれ?JRE?


posted at 23:42:48


今日はダウンロードとインストールで終わりそうな予感。


posted at 23:43:53


とりあえずJDKいれて、JAVA_HOMEとPath通した。


posted at 23:47:09



日付変わる。

あれ、create-domain-class コマンドがない??


posted at 00:02:13


ああ、そういうことか。create-appの後はアプリのルートディレクトリに移動しなくちゃいけない。当たり前だな。


posted at 00:04:52


HelloWorldで早速はまったナリ。


posted at 00:15:48


読むのとやるのじゃ大違い。


posted at 00:18:53



ハマった。
理由: 何も知らずに c:\grails-app というディレクトリを作成し、その下にgrailsのアプリと作ろうとしたらコンパイルできない状態になった。
grails create-app すると grails-app というディレクトリができるがその名前と重複してるのが悪いのだろうか? 新しく他の名前にしたところすんなり動いた。

やっと、HelloWorldできた。どうやらアプリ用に区切ったディレクトリ名がgrails-appにしてたのが問題っぽい。create-appで同じ名前のgrails-appというのが自動生成されてるのでどっちかわからなかったのかな?


posted at 00:38:17



深夜のため愚痴が増える。

っていうかマシンが劇重。


posted at 00:47:04


エラー文言固いな。 [class Member]クラスのプロパティ[name]の空白は許可されません。


posted at 00:48:53


web flow 使う前提だと generate-all とか逆に使いにくいな。


posted at 00:51:43



最終的に generate-all しちゃったほうがイイかなという結論に。
理由は Web Flow の使用は複雑な遷移やflowスコープを利用したデータ登録時だけでいいと思うから。
それ以外は Web Flow を使わないほうが楽。


続き。マシンが絶不調。Web Flow の動きと View の関連が分からず終了。
代わりにAuto Reloadingなど内部の仕組みをちょっと調べる。
自動リロード(Auto Reloading)については以下のURLを参照
Grails - Japanese Auto Reloading

だめだこのマシン。Jetty起動したら固まる。


posted at 01:09:53


とりあえず今日はここまで。Web Flowもっと調べる必要ありだな。


posted at 01:10:22


もっと速いマシンがほしい。


posted at 01:11:28


メモ。 http://bit.ly/3mNJCj


posted at 01:55:12


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


sitemesh=org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter


posted at 02:16:09


urlMapping=org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter


posted at 02:16:15


web.xmlのフィルター


posted at 02:16:29



起床。ちょっとニュースを読んだ後、Grails再挑戦。

むっくり


posted at 07:54:30


GaelykとGAE Pluginどちらが使いやすいのだろう。調べなきゃ。


posted at 08:39:47



Web Flowの動きがやっと掴める。

徐々に分かってきた。Web Flowに入るには redirect(action: "xxxFlowのxxx部分") Flow毎に階層が分けられて、views/controller/flow/state.gsp になる 全部Flowを使う必要なく遷移が複雑になるところに使うと良い


posted at 10:16:34


Grails分かれば簡単。魔法を覚えるまでがちょっと大変かな。


posted at 11:08:34


データ登録系はWeb Flowを使うのかな。取ってきた値をbindDataして突っ込むと。validateも簡単。あとはvalidateが柔軟に使えるかどうか、だ。


posted at 11:11:25


ふむ。複数のConstraintsはカンマ区切りでOKっと。 ex) email(blank:false, email:true)


posted at 11:19:54



Constraintsをカスタマイズしたくなる。Pluginがあったのでインストール。
エラーが出力される順番が変なことに気付く。

Constraints は Grails Custom Constraints が便利そう。


posted at 11:26:50


インストールする grails install-plugin constraints


posted at 11:28:15


おお、すげ。Custom Constraints Plugin 便利だ。


posted at 11:38:07


g:renderErrorsのエラーが出る順番を変えたい・・・。 #grails


posted at 11:41:12


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


簡単なマスタメンテなら一瞬でズガンと作れる。テンプレートの調整するだけで済むのか。


posted at 11:51:57


まぁこれはrailsも同じ。


posted at 11:52:10


うーん、確認画面から入力画面に戻ったときに値をどうやって戻すのかがわからない #grails


posted at 13:27:25



昼食後、午前中に悩んだ 入力→確認→入力 に戻ったときに入力された値が入らない問題が一瞬で解決される。

昼飯食ってGrails再開。値が戻らない理由は g:form に action を指定していなくて最初の画面に遷移してたからというしょーもない理由。


posted at 14:06:29


うわ。できた。登録&一覧は一瞬で出来た。


posted at 14:24:12



とりあえず終わり。

Grailsはとりあえずここまで。昨日の夕方に「Grails徹底入門」買って半日である程度使い方分かったので、最初の敷居はそんなに高くなさそう。


posted at 14:32:32


ただ、Spring, Hibernateらへんの知識は仕事で使うなら必須になるだろうな。


posted at 14:33:00


ActiveRecordパターンって楽だけど、なんか気持ちわるい。多分SQLを書かずに出来ちゃうからかな。2Way-SQLで書けないのかな?


posted at 14:54:15


DBFluteでいう 外だしSQL みたいなー。


posted at 14:54:38




作ったサンプル
 一覧、会員登録(入力→確認→完了)



■ドメインクラス 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>