Fixtures
Playではエンティティの初期データ作成のために Fixtures という仕組みが提供されている。Rails と同様。test/data.yml に以下の YAML ファイルを用意。
# Test data User(bob): email: bob@gmail.com password: secret fullname: Bob isAdmin: true User(jeff): email: jeff@gmail.com password: secret fullname: Jeff Post(firstBobPost): title: About the model layer postedAt: 2009-06-14 author: bob content: > The model has a central position in a Play! application. It is the domain-specific representation of the information on which the application operates. Martin fowler defines it as : Responsible for representing concepts of the business, information about the business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software. Post(secondBobPost): title: Just a test of YABE postedAt: 2009-03-25 author: bob content: > Well, it's just a test. Post(jeffPost): title: The MVC application postedAt: 2009-06-06 author: jeff content: > A Play! application follows the MVC architectural pattern as applied to the architecture of the Web. This pattern splits the application into separate layers: the Presentation layer and the Model layer. The Presentation layer is further split into a View and a Controller layer. Comment(c1): author: Guest content: > You are right ! postedAt: 2009-06-14 post: firstBobPost Comment(c2): author: Mike content: > I knew that ... postedAt: 2009-06-15 post: firstBobPost Comment(c3): author: Tom content: > This post is useless ? postedAt: 2009-04-05 post: secondBobPost
Fixtures の利用
Fixtures は以下で YAML からエンティテイの情報を読み込み永続化できる。
Fixtures.load("data.yml");
/test/BasicTest.javaに以下のテストメソッド追加。
@Test public void fullTest() { Fixtures.load("data.yml"); // Count things assertEquals(2, User.count()); assertEquals(3, Post.count()); assertEquals(3, Comment.count()); // Try to connect as users assertNotNull(User.connect("bob@gmail.com", "secret")); assertNotNull(User.connect("jeff@gmail.com", "secret")); assertNull(User.connect("jeff@gmail.com", "badpassword")); assertNull(User.connect("tom@gmail.com", "secret")); // Find all bob's posts List<Post> bobPosts = Post.find("author.email", "bob@gmail.com").fetch(); assertEquals(2, bobPosts.size()); // Find all comments related to bob's posts List<Comment> bobComments = Comment.find("post.author.email", "bob@gmail.com").fetch(); assertEquals(3, bobComments.size()); // Find the most recent post Post frontPost = Post.find("order by postedAt desc").first(); assertNotNull(frontPost); assertEquals("About the model layer", frontPost.title); // Check that this post has two comments assertEquals(2, frontPost.comments.size()); // Post a new comment frontPost.addComment("Jim", "Hello guys"); assertEquals(3, frontPost.comments.size()); assertEquals(4, Comment.count()); }
起動時の初期データ
Fixtures は起動時の初期データ投入にも利用できる。
/app/Bootstrap.java に以下を作成。
import play.*; import play.jobs.*; import play.test.*; import models.*; @OnApplicationStart public class Bootstrap extends Job { public void doJob() { // Check if the database is empty if(User.count() == 0) { Fixtures.load("initial-data.yml"); } } }
Play の Job は HTTP リクエストとは別に特定の条件で起動するcron jobとして利用できる。上記は @OnApplicationStart アノテーションによりアプリケーションのスタート時に自動実行される。
Playの起動モードは DEV と PROD モードがあり、DEVモード時には初回のHTTPアクセス時にデータ作成が行われる。PROD モードの場合にはアプリケーションの起動時となる。DEV モードではアクセス時のブラウザ画面にてエラーの原因を表示するため。
テストデータ用のYAMLは/conf/initial-data.yml に、前述のdata.yml の内容で作成。
トップページの作成
/app/controllers/Application.java を変更してトップページのコントローラを作成。
public class Application extends Controller { public static void index() { Post frontPost = Post.find("order by postedAt desc").first(); List<Post> olderPosts = Post.find( "order by postedAt desc" ).from(1).fetch(10); render(frontPost, olderPosts); } }
render の引数として取得した情報を渡している。
これらの情報を表示するページテンプレートを編集 /app/views/Application/index.html
#{extends 'main.html' /} #{set title:'Home' /} #{if frontPost} <div class="post"> <h2 class="post-title"> <a href="#">${frontPost.title}</a> </h2> <div class="post-metadata"> <span class="post-author">by ${frontPost.author.fullname}</span> <span class="post-date">${frontPost.postedAt.format('MMM dd')}</span> <span class="post-comments"> | ${frontPost.comments.size() ?: 'no'} comment${frontPost.comments.size().pluralize()}</a> #{if frontPost.comments} , latest by ${frontPost.comments[0].author} #{/if} </span> </div> <div class="post-content"> ${frontPost.content.nl2br()} </div> </div> #{if olderPosts.size() > 1} <div class="older-posts"> <h3>Older posts <span class="from">from this blog</span></h3> #{list items:olderPosts, as:'oldPost'} <div class="post"> <h2 class="post-title"> <a href="#">${oldPost.title}</a> </h2> <div class="post-metadata"> <span class="post-author"> by ${oldPost.author.fullname} </span> <span class="post-date"> ${oldPost.postedAt.format('dd MMM yy')} </span> <div class="post-comments"> ${oldPost.comments.size() ?: 'no'} comment${oldPost.comments.size().pluralize()} #{if oldPost.comments} - latest by ${oldPost.comments[0].author} #{/if} </div> </div> </div> #{/list} </div> #{/if} #{/if} #{else} <div class="empty"> There is currently nothing to read here. </div> #{/else}
Fixtures にて設定したデータが表示されていることが分る。