decadence

個人のメモ帳

Play2.1.x 以降で Playサブプロジェクトを用いる

ちょっと試した後の注意点・疑問点とか数点書いてるだけ

経緯

Play2.0.xを使っていて,Play2.2.xへと適当に移行をした
大々的なサイトでなく適当に作っているページなんで,細かなプロジェクトページみたいなものがあると楽だった
Playはsbtを用いている事から,始める sbt - マルチプロジェクト・ビルドのようにして,モジュール毎に別プロジェクトとして分離する事が出来た
さらに,routingから何やらまで含んだPlayのプロジェクトもPlay2.1.xなどのドキュメントにある通り分離が出来る

使用ケース

以上から,webサイトのpath毎に違うプロジェクトとして開発を行うことが出来る
実際に大本となるプロジェクトのroutesを用いて表すと以下のようなroutingが行える

# Home page
GET     /                       controllers.Application.index

# Admin page
->      /admin/                 admin.Routes

# Services
->      /sub/                   sub.Routes

ここでは大本となるサイトとは別のPlayProjectとして管理用Playプロジェクト,別サービスとしてのPlayプロジェクトなどを想定している
個人で適当なサイトを作りつつ変なサービスを増やしたい時,サブドメインやら増やしてポートを変えてリバースプロキシで分ける...といった事も可能だが,面倒なのでpath毎にサービスを分けたい時に,開発を行うコードも分離出来るのが非常に良い
テストもdependsOnやaggregateを用いて,分離出来るのが非常に良い
どこかで/api/に対して別のプロジェクトを割り当ててる例なども見た

やること

ともかく,以下のドキュメントに書いてある通りにやるのが全てではある.
SBTSubProjects

以下では上記のドキュメントを基に,数点細かな注意点・疑問点を述べる

サブプロジェクトにおけるroutes

adminというサブプロジェクトのroutesは,`conf/admin.routes`といった名前で保存され,root projectからは`admin.Routes`のように参照される事になるだろう
普通にブラウザから見る分にはこれだけで充分なのだが,恐らくroot projectと同じテストを書いたとしても,このままではきちんと個々のサブプロジェクトにおけるroutingが解決されない
追記すべきは,adminというサブプロジェクトに対する`conf/application.conf`に対する設定である

application.router=admin.Routes

上記のような記述を追加する事で,サブプロジェクトに対するroutingの解決が行なわれる
また,他のサブプロジェクト固有の設定についても適宜追記すると良いだろう

root projectのapplication.confに上記のようなrouterの設定を書かないと面白い事に,runすると通常通り動くが,startするとサブプロジェクトのみしか動かないものが立ち上がる
root projectのapplication.confにも以下のようにrouterの設定を書くべき

application.router=Routes

viewsにおけるmodelsの呼び出し

adminというサブプロジェクトにおいて,app/models/admin/SubprojectUser.scalaにモデルを用意した際,以下のようにテンプレートへの引数にそのモデルを渡したい事があるかもしれない

@(users: Seq[SubprojectUser])(implicit flash: Flash)

@*********************
 * 以下HTMLテンプレート *
 *********************@   

サブプロジェクトでないPlayプロジェクトならばコンパイルが通るのだが,残念ながらこれはコンパイルが通らない

引数が1行目と決められているためにimportも出来ず,以下のような記述を行う事でなんとかコンパイルを通す事が出来る

@(users: Seq[models.admin.SubprojectUser])(implicit flash: Flash)

どこかにviewsで参照すべきimport文をまとめて書けないのか

Play サブプロジェクトのパッケージとディレクトリ構成

ドキュメント通り,adminという名前のプロジェクトには,controllersにはcontrollers.adminといったパッケージ名を,viewsにもviews.adminといったパッケージ名を使う事になる.
特にviewsに対して各種テンプレートをadminというサブプロジェクト内においては

app/views/admin/index.scala.html

といったディレクトリに配置する.パッケージ名から考えると当然ではあるが,通常のPlayProject同様に`app/views/index.scala.html`のような配置にすると,root projectに用意されたindex.scala.htmlが呼び出されてしまう

ディレクトリ構造を基にviewsではパッケージ名が決まるらしくて、controllerからは以下のように呼び出す

def index = Action {
  Ok(views.html.admin.index())
}
サブプロジェクトにおけるroutesの逆引き

通常のPlayプロジェクトにおけるroutesの逆引きは

Redirect(routes.Application.index)

のように行なわれる

今回見るべきroutesはここではなく,adminというサブプロジェクトにおいては,`controllers.admin.routes`になる.つまり,

Redirect(controllers.admin.routes.Application.index)

が正しい内容となる

面倒なので`import controllers.admin._`もしくは`import controllers.admin.routes`などとしたい
前者であればcontrollers.adminというpackageにおいて,このimport文を記述をしなければならないってのはなんだ...
後者であれば以下のようなwarningが

[warn] imported `routes' is permanently hidden by definition of object routes in package admin

取り敢えずimportせずに書いてる