Boardsのindex.gsp
今度は、hasManyで関連付けているBoardsのindex.gspです。ここでは、各記事へコメントした人の名前をそれぞれ表示させることにしましょう。
<body> <h1>Grails Boards</h1> <h2>テーブルの一覧リスト</h2> <table width="400"> <g:each in="${tableData}" status="i" var="record"> <tr> <td>${record.id}</td> <td>${record.name}</td> <td>${record.title}</td> <td> <g:each in="${record.comments}" status="j" var="comment"> <div style="size:-1;">${comment.name}</div> </g:each> </td> </tr> </g:each> </table> </body>
ここでは、まず<g:each>を使い、tableDataからBoardsインスタンスを順に取り出して表示をしていきます。コメントをつけた人の名前は、
<g:each in="${record.comments}" status="j" var="comment">
このようにして繰り返し処理をしています。ここでは、record.commentsとしてrecordのcommentsからインスタンスを取り出しています。commentsというプロパティは、Boardsにはありませんでした。が、hasMany = [comments:Comments]としてhasManyを設定していましたね。これにより、取得されたCommentsインスタンスがcommentsとして設定されていたのです。
こうしてcommentに取り出したインスタンスから、${comment.name}としてnameの値を取り出し書き出していけば、関連するCommentsのnameをすべて出力できます。
showアクションの作成
hasManyで関連付けられたレコードの処理がわかったところで、応用例として「特定の投稿と、それへのコメントをまとめて表示する」アクションを作ってみましょう。BoardsControllerにこのようにアクションのクロージャを追加します。
def show = { [record:Boards.get(params.id)] }
送信されたid
パラメータを使ってBoardsからレコードをgetし、それをrecordとしてビューに渡しています。show.gspでは、渡されたrecordをもとに、投稿データと、コメントのデータをそれぞれテーブルにまとめて表示します。
<body> <h1>Grails Boards</h1> <h2>ID=${record.id}の内容</h2> <table width="400"> <tr width="100"><td>ID</td><td>${record.id}</td></tr> <tr><td>名前</td><td>${record.name}</td></tr> <tr><td>タイトル</td><td>${record.title}</td></tr> <tr><td>内容</td><td>${record.content}</td></tr> </table> <h3>コメント</h3> <table width="400"> <g:each in="${record.comments}" status="i" var="comment"> <tr> <td width="20">${comment.id}</td> <td width="80">${comment.name}</td> <td>${comment.message}</td> </tr> </g:each> </table> </body>
アクセスする際、「show?id=番号」というようにして、表示するID番号を指定すると、Boardsからその番号のレコードを取り出して表示し、さらにその記事へのコメントをComentsからすべて取り出して表示します。コメントは、<g:each>で${record.comments}からインスタンスを順に取り出して処理しています。このように、hasManyやbelongsToを使えば、コントローラー側でただgetして値をビューに渡すだけで、必要なレコードがすべて用意されます。複数レコードを組み合わせた処理が非常に単純な操作で作れることが実感できるでしょう。
まとめ
今回説明して分かるように、Grailsの場合、バリデーションはレコードの保存とセットで機能します。従って、ドメインクラスと無関係のフォームなどでバリデーションを行う場合には、別途考えなければいけません。今回の説明は、あくまでドメインクラスの保存時のバリデーションと考えてください。
リレーションシップについては、まずはhasManyとbelongsToによる1対多、多対1の結合を実際に自分で作成して確かめてみるとよいでしょう。Grailsは、リレーションシップはこの2つの組み合わせで実現します。
従来、こうした結合は、SQLでJOINを用いて行いました。このJOINの考え方にとらわれるあまり、「LEFT JOINに相当する機能は……、INNER JOINは……」と探し回ってしまう人も多いのではないでしょうか。Grailsでは、各JOINごとに対応するリレーションシップが用意されているわけではありません。両者の主従関係からリレーションシップを考えるようにしましょう。