Bootstrap3のtooltipをajax後でも動かす

 

初回表示時にtooltipを出す例はBootstrapのサイトでも紹介されているのですが、Ajaxで書き換えた後でも表示する方法がわかったのでメモしておきます。

初回表示時にtooltipを仕込むための処理

まずは最初にやっていたやつ。

$ ->
  $('[data-toggle="tooltip"]').tooltip()

これはAjaxに対応していません…。

Ajaxによる画面書き換えにも対応したtooltipを仕込む処理

次に、Ajaxに対応したやつ。これは、bodyタグに対してイベントを仕込み、オプションでselectorを指定しています。Bootstrap3のオプションの説明でも書いてありますが、動的なHTMLに対応できるようになる、と書いてあります。

Bootstrap3: tooltip-options

$ ->
  $('body').tooltip(
    selector: '[data-toggle="tooltip"]'
  )

思ったよりも簡単に対応できてよかったです。さすがBootstrap3。


Grailsでdomainのテストを行う

ScaffoldしたBookのテストを行ってみようと思ったので、とりあえずdomainのテストを書いてみました。テストの方法は、Grailsのドキュメントとqiitaの記事を参考にしました。

参考ページ:

前回で

grails create-domain-class example.Book

を行っていたので、自動的にsrc/test/groovy/example/BookSpec.groovyができているはずです。自動で作られたテストは絶対に落ちるように作られているので、とりあえず実行してみましょう。

grails test-app example.BookSpec

Tests FAILEDと言われました。ここからがスタートです。

domainのテストでなにをテストするのか?

まだちゃんと勉強していませんが、ビジネスロジックはおそらくServiceで実装するのかなと思うので、domainのテストは制約(Constraints)のテストかなと思います。バリデーションのテストはValidatableTraitを使っている場合にはそちらをやるっぽい?(汎用的なバリデーションを使い回すときとか)

一気にやるのは私は苦手なので、範囲を細かく、まずdomainだけやります。

おさらい。Book Domainの定義について

Book Domainですが、以下のように定義していました。

package example

class Book {

    String title
    String content
    Integer price
    Date published

    static constraints = {
        title       blank: false,   nullable: false, size: 1..10
        content     blank: true,    nullable: true
        price       blank: true,    nullable: true
        published   blank: true,    nullable: true
    }
}

Book Domainのテストを定義する

Book Domainでのテスト項目は、

  • タイトルが必須であること
  • タイトルが10文字以内であればOK
  • タイトルが11文字以上であればNG

ということくらいですね。

ということで、参考サイトを元にとりあえずこんな感じで書いてみました。

package example

import grails.test.mixin.TestFor
import spock.lang.Specification

/**
 * See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
 */
@TestFor(Book)
class BookSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    void "データの検証を行う"() {
        when: 'タイトルがない場合'
        def book = new Book()

        then: '検証が失敗すること'
        !book.validate()

        when: 'タイトルがある場合'
        book = new Book(title: '楽しいGroovy')

        then: '検証が成功すること'
        book.validate()

        when: 'タイトルが11文字以上の場合'
        book.title = "a" * 11

        then: '検証が失敗すること'
        !book.validate()

        when: 'タイトルが10文字以内の場合'
        book.title = "a" * 10

        then: '検証が成功すること'
        book.validate()
    }
}

テストを実行する

では実行してみましょう。

grails test-app example.BookSpec

そうすると、以下のような結果になりました。

:compileJava UP-TO-DATE
> Building 11% > :compileGroovy > Resolving dependencies ':compile' > Resolving dependencies 'detachedConfiguration:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
> Building 55% > :compileTestGroovy > Resolving dependencies ':testCompile' > Resolving dependencies 'detachedConfi:compileTestGroovy
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

| Tests PASSED

成功した模様です。

まとめ

とりあえずテストのとっかかりを覚えておくと、テストを書くことへの面倒臭さを抑えることができるかなと思います。ドメインのテストは短くてすみそうなのでチャチャっとやってみましょう。


Grails3.0.4でscaffoldを作成する

ひとまず、Grailsに慣れることを優先しようと思ったので、Scaffoldを作ってみました。

ドメインクラスの作成

まず、ドメインを作ります。ドメインとは、MVCのModelの部分に当たります。Grailsでは、Modelをドメインとサービスに分けているようです。ここは今後勉強していこうとおもいます。ドメインクラスを作るのは、createコマンドが準備されているので、それを使いました。

grails create-domain-class example.Book

これで、grails-app/domains/example/Book.groovyが作られました。

ドメインクラスにてテーブル定義を行う

ドメインクラスにメンバ変数を設定して、テーブル定義と制約を書いていきます。

package example

class Book {

    String title
    String content
    Integer price
    Date published

    static constraints = {
        title       blank: false,   nullable: false, size: 1..10
        content     blank: true,    nullable: true
        price       blank: true,    nullable: true
        published   blank: true,    nullable: true
    }
}

すごく適当に作りました。タイトルと、内容と、値段と、発売日ですね。constraintsブロックに、制約を書いていきます。お試しなので、タイトルのみ必須で、タイトルは10文字以下にしました。データベースはデフォルトのH2を使っており、アプリの起動時にメモリ上に作られ、終了時に全部削除されます。お試しでやる分には十分なのでこのままにしていますが、永続化したくなったらPostgresqlにでもします。それは今度の話にします。

とりあえずこれでいいでしょう。

Scaffoldを作成する

では、このドメインのScaffoldを作ってみましょう。

grails generate-all example.Book

バーッと処理が走って色々できました。
では、grailsを起動します。

grails run-app

起動したら、 http://localhost:8080/books/ にアクセスしてみます。

インデックス

なにもないので作成を押します。

作成画面

作成画面。タイトルだけ必須になってます。blank: falseにしたからですね。入力項目は、発売日をDate型にしているので、日付を選択するためのセレクトボックスが自動で作られています。値段もIntegerにしているので、input type=numberになっている模様。

閲覧画面

作成完了画面。サクッとデータが登録できていいですね。
では今度はサクッと消してみます。削除確認ダイアログが表示されたので、はいを押します。

削除済み画面

削除完了画面。結果が表示されています。

まとめ

Scaffoldを作ってデータを登録するところはRailsと同じで非常に簡単でした。
Viewを修正したりなどはまだ行っていないので、後日試してみます。
せっかくBootstrap3入れたし。


GrailsでBower Webjarsを使う!

昨日の続きみたいなもんですが、Grailsでbootstrap-sassを使いたいのだけれど、どうしたらいいかなーと思っていたんですが、前にspring bootの練習をしていたときにWebJarsというのがあったなというのを思い出したので、それを使ってみることにしました。WebJarsっていうのは、JavaScriptのライブラリをmavenやgradleを使って管理しようという仕組みです。Railsでいうところのrails-assetsみたいなもんですね。

http://www.webjars.org/

その中で、Bower WebJarsというのがありました。Classic WebJarsは、WebJarsチームがOK出したものが登録されていくけれど、Bower WebJarsは誰でも登録可能のようで、最新のバージョンのライブラリが使えます(Classic WebJarsはバージョン対応がやや遅れ気味っぽい)。今回は、Bower Webjarsを使ってみます。

Bower WebJarsで使いたいライブラリを探す

bower_webjars_howto_use

  1. http://www.webjars.org/より、Bower WebJarsに移動します。
  2. ライブラリ検索フィールドにライブラリ名を入力します。
  3. 使いたいライブラリのバージョンを選択します。
  4. 使っているビルドツールを選びます。今回はgradleです。
  5. 表示された内容を、build.gradleに貼り付けます。

こんな感じでじゃんじゃん調査します。

build.gradleの修正

build.gradleのdependenciesブロックに、jqueryとbootstrap-sassを追加しました。

dependencies {
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"

    compile "org.grails.plugins:hibernate"
    compile "org.grails.plugins:cache"
    compile "org.hibernate:hibernate-ehcache"
    compile "org.grails.plugins:scaffolding"

    compile 'org.webjars.bower:jquery:2.1.4'
    compile 'org.webjars.bower:bootstrap-sass:3.3.4'

    runtime "org.grails.plugins:asset-pipeline"
    runtime 'com.bertramlabs.plugins:sass-asset-pipeline:2.3.1'
    runtime 'com.bertramlabs.plugins:coffee-asset-pipeline:2.0.7'

    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"

    // Note: It is recommended to update to a more robust driver (Chrome, Firefox etc.)
    testRuntime 'org.seleniumhq.selenium:selenium-htmlunit-driver:2.44.0'

    console "org.grails:grails-console"
}

application.js.coffeeの修正

Bower WebJarsで取り込んだjqueryとbootstrap-sassを読み込みます。

#= require webjars/jquery/2.1.4/dist/jquery.min
#= require webjars/bootstrap-sass/3.3.4/assets/javascripts/bootstrap.min
#= require_self
#= require_tree .

$ ->
  $('#spinner').ajaxStart(->
    $(this).fadeIn()
  ).ajaxStop( ->
    $(this).fadeOut()
  )

上記のように書けばOKなのですが、じゃあjqeury.minへのパスやbootstrap.minへのパスってどうやって調べたのか?というところが気になると思います。指定方法がわからなくて困りましたので、皆さんが時間を無駄にしなくてもいいように書いておきます!ヒントはBower WebJarsのfilesにありました。

Bower Webjarsのfilesのリンク

filesをクリックすると、ファイルの一覧がズラーッと表示されます。その中で、読み込みたいファイルを見つけて、そのファイルパスをコピペしましょう。ここではbootstrap-sassを対象にしていますが、jqueryの場合も同様の手順でパスを調べました。

Bower WebJarsを使用時のファイルパスを調べる方法

あと、ここまでやれば、もともとあったjqueryは必要なくなるので、grails-app/assets/javascripts/以下にあるjquery.jsは削除しときましょう。

application.scssの修正

さて、次にapplication.scssの修正ですが、こっちのほうが厄介でした。というのも、bootstrap-sassはglyphiconがあるので、それの読み込み方法を設定しなければならないためです。以下のようにすれば問題ありません!

まず、grails-app/assets/stylesheets以下に、_variables.scssを作成します。そして、以下のように記述します。

@import 'webjars/bootstrap-sass/3.3.4/assets/stylesheets/bootstrap/variables';
$icon-font-path: "webjars/bootstrap-sass/3.3.4/assets/fonts/bootstrap/";

@importは必要ないかもしれませんが、今後、ほかの変数を修正した場合にエラーを出さないために事前に読み込んでおきました。
肝は、アイコン用フォントパスを指定している変数の値をBower WebJarsに合わせて修正しておくことです。

次に、application.scssを修正します。

@import 'variables';
@import 'webjars/bootstrap-sass/3.3.4/assets/stylesheets/bootstrap';

これで、めでたくbootstrap3が使えるようになりました!

まとめ

まだ全然Grailsに関係ないところですが、フロント側がある程度できるような環境が整えば、やる気が出てくると思うので、先にやっときましょう!


Grails 3.0.4でCoffeeScript,SASSを使えるようにした

岡山でgroovyやってる人があんまりいないからちょっとやってみるか、というくらいの気持ちでgroovyの勉強を始めようと思い、とりあえずGrailsを使ってみることにしました。といってもまだアプリを作ってないですが、とりあえず素のJavaScriptとCSSは嫌だなぁと思っていたので、CoffeeScriptとSASSを使えるようにしてみました。

groovyとGrailsのインストール

groovyとgrailsはgvmを使ってインストールしました。

まずはgvmのインストール。

curl -s get.gvmtool.net | bash

次に、groovyとgradleとgrailsのインストール。

gvm install groovy
gvm install gradle
gvm install grails

Grailsプロジェクトの作成

次に、grailsプロジェクトを作成してみます。

grails create-app sample

その後、プロジェクトに必要なファイルを入れるために、プロジェクトディレクトリに移動した後、grailsコマンドを打ちます。

cd sample
grails

grailsのコンソールが起動するためにライブラリのダウンロードが走ります。結構時間かかります。

grailsのコンソールでrun-appと打つなどして、grailsを起動させてみましょう。終わったら、Ctrl+Cで終わらせます。

build.gradleの修正

CoffeeScript、SASSを動くようにするためにbuild.gradleを修正します。
Grailsのバージョンが3になって、1,2系のプラグインとの互換性がなくなったみたいです。gradleでインストールする際に、bintrayを使いましょうというふうに書いてありました。なので、mavenのリポジトリにbintrayのurlを追加します。repositoriesブロックを修正します。

repositories {
    mavenLocal()
    maven { url "https://repo.grails.org/grails/core" }
    maven { url "http://dl.bintray.com/bertramlabs/asset-pipeline" }
}

次に、buildscriptブロックを修正します。
coffee-asset-pipelineとsass-asset-pipelineを追加します。

buildscript {
    ext {
        grailsVersion = project.grailsVersion
    }
    repositories {
        mavenLocal()
        maven { url "https://repo.grails.org/grails/core" }
        maven { url "http://dl.bintray.com/bertramlabs/asset-pipeline" }
    }
    dependencies {
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath 'com.bertramlabs.plugins:asset-pipeline-gradle:2.1.1'
        classpath 'com.bertramlabs.plugins:coffee-asset-pipeline:2.0.7'
        classpath 'com.bertramlabs.plugins:sass-asset-pipeline:2.3.1'
    }
}

次に、runtimeの記述を追記します。dependenciesブロックを修正します。

dependencies {
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"

    compile "org.grails.plugins:hibernate"
    compile "org.grails.plugins:cache"
    compile "org.hibernate:hibernate-ehcache"
    compile "org.grails.plugins:scaffolding"

    runtime "org.grails.plugins:asset-pipeline"
    runtime 'com.bertramlabs.plugins:sass-asset-pipeline:2.3.1'
    runtime 'com.bertramlabs.plugins:coffee-asset-pipeline:2.0.7'

    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"

    // Note: It is recommended to update to a more robust driver (Chrome, Firefox etc.)
    testRuntime 'org.seleniumhq.selenium:selenium-htmlunit-driver:2.44.0'

    console "org.grails:grails-console"
}

assetsでコンパイルされるファイルの対象を設定しておきます。基本的にscssファイルは除外し、application.scssのみ対象とします。

assets {
    minifyJs = true
    minifyCss = true
    excludes = ['**/*.scss']
    includes = ['application.scss']
}

とりあえずここまで。

application.js.coffeeとapplication.scssを作成

grails-app/assets/javascripts/application.jsを削除し、application.js.coffeeを作成と、grails-app/assets/stylesheets/application.cssをリネームしapplication.scssにします。

#= require jquery-2.1.3.js
#= require_self
#= require_tree .

# application.jsにあった処理を一応coffeescriptにしておく
$ ->
  $('#spinner').ajaxStart(->
    $(this).fadeIn()
  ).ajaxStop( ->
    $(this).fadeOut()
  )

application.scssはリネームするだけですが、一応載せておきます。

/*
*= require main
*= require mobile
*= require_self
*/

これで終わりです。一応、grails run-appしてみましょう。ちゃんと動けばOKです。

まとめ

ここまでやるんならRailsでいいような気がしてきた…(オィ