連載
» 2008年09月26日 00時00分 公開

Railsコードリーディング〜scaffoldのその先へ〜(1):コードリーディングを始めよう (2/3)

[倉貫 義人, 松村 章弘,TIS株式会社 技術本部 基盤技術センタ]

グループ機能を見てみよう

 今回は、SKIPの中心機能の1つである「グループ機能」のソースコードを読んでいくことにします。

 グループ機能とは、mixiでいうところの「コミュニティ」に相当します。SKIPは、社内利用を想定したSNSということで、コミュニティだけでなく、業務用のプロジェクトや部門グループなどで使えるように、「グループ」という名前にしています。グループ機能の特徴とできることは、以下のとおりです。

●SNSのユーザーであれば、誰でもグループを作成できる

●グループには以下の機能がある

  • 掲示板を使って、グループ内の議論や情報共有ができる
  • ファイル共有機能を使って、グループ内でファイルを共有できる

●グループの設定には以下の2種類が選ぶことができる

  • 誰でも自由に参加できるグループ
  • グループ管理者の参加承認が必要なグループ

●グループは、管理者の指定で分類ができる。以下がデフォルトの分類

  • ビジネス(業務での利用を想定しています。例:プロジェクト)
  • ライフ(業務外の社内活動での利用を想定しています。例:クラブ活動、勉強会)
  • オフ(業務外のコミュニケーションのための利用を想定しています。例:同好会)

 SKIPのデモサイトを使って、動きを確認してみましょう。まず、既定のユーザーでログインを済ませた後、右側のメインメニューから「グループ」をクリックします。すると、一覧画面が表示されます。ここでは、条件を入れることで検索も可能です。

 次に、上部タブの「グループの新規作成」をクリックします。ここから、新しいグループを作ることができます。グループの識別子や名前、説明などを入力してグループの作成ができます。

 試しに、グループを1つ作成してみましょう。デモサイトですので、気にすることなく作ってしまいましょう。うまく作れたら、グループのサマリの画面に移動しているはずです。

 先ほど入力したグループの説明文などの変更は、「管理」タブから行えます。また、グループの削除も同じ画面から行うことができます。

 ここまでで、グループを作成したり削除したりする際の基本的な動きは終了です。ここで紹介した機能は、グループの新規作成、表示、更新、削除の4つの基本機能でした。これらは、総称して「CRUD」(Create/Read/Update/Delete)と呼ばれています。今回は、連載の1回目ということもあるので、グループ機能を例に基本的な動作であるCRUDのソースコードの説明をします。

グループの一覧・検索

 グループの一覧表示の画面からソースコードを見ていきます。グループの一覧表示の状態でWebブラウザのURLを見てみます。

  http://www.openskip.org/demo/groups

 デモサイトの場合、上記のようになっているはずです。自前で構築した方はドメインのところが違うだけだと思います。このURLを解析することで、どのソースコードを読むべきかが分かります。

 このURLの場合、groups_controllerのindexというメソッドが呼ばれることが想定されます。メソッド名の指定が特にない場合は、indexメソッドが呼ばれるような規約になっています。

 このURLとコントローラ/メソッドの関係については、configディレクトリ以下のroutes.rbの設定を変更することで振る舞いを変えることが可能ですが、特に何も設定しなくてもデフォルトの動作として規約が設定されているのです。これが、「設定より規約(CoC)」と呼ばれている部分の一例です。

 では、groups_controllerのindexメソッドを見ていきましょう。

01   def index
02     params[:yet_participation] ||= false
03     params[:group_category_id] ||= "all"
04     params[:sort_type] ||= "date"
05     @format_type = params[:format_type] ||= "detail"
06     @group_counts, @total_count = Group.count_by_category
07     @group_categories = GroupCategory.all
08
09     options = Group.paginate_option(session[:user_id], params)
10     options[:per_page] = params[:format_type] == "list" ? 30 : 5
11     @pages, @groups = paginate(:group, options)
12 
13        flash.now[:notice] = '該当するグループはありませんでした。'
14       flash.now[:notice] = '該当するグループはありませんでした。'
15    end
16   end
   app/controllers/groups_controller.rb

 最初の4行(2〜5行目)はパラメータに初期値を設定しています。このindexにリクエストパラメータを付けずに呼び出した場合、デフォルトの検索結果としてすべてを表示するような動きになっています。

 次の行(6行目)は、Groupクラスのcount_by_categoryメソッドを使って、グループのカテゴリごとの件数と、全グループのトータル件数を取得しています。このcount_by_categoryメソッドは、SKIPチームが独自に作ったクラスメソッドです。そこで得た値を、@group_countsと@total_countというインスタンス変数に代入しています。こうすることで、情報をビューに引き継いでくれます。

 メソッドの戻り値が2つあるのは、Javaのプログラマからすると、少し不思議な感じがしますが、大変便利に使うことができるRubyの特徴の一つです。

 その次の2行(8〜9行目)は、classic_paginationという機能を使う際の、そのメソッドの引数となる条件を準備しているところです。Groupクラスのpaginate_optionという自作のメソッドを呼んでいます。グループ機能の一覧表示の動きを見てみると分かりますが、5件以上のデータがある場合には「次のページに進む」というリンクが出てきます。

 この複数ページがある場合のページ繰りの処理をpaginationと呼びます。以前のRailsには標準で備わっていた機能でしたが、Rails 2.0のバージョンアップの際に、プラグインとして実現するように変更されました。

 SKIPでは、Railsのバージョン1.0のころから備えていたpaginationを実現するために、classic_paginationというプラグインを利用しています(今後はwill_paginateプラグインに置き換えていきます)。

 次の行(10行目)では、実際にpaginateメソッドを呼び出しています。1つ目の引数に対象のモデルを指定し、引数に先ほど準備したオプションを指定します。こちらも、結果をインスタンス変数に代入しています。

 最後の3行(12〜14行目)は、paginateメソッドの結果の変数をチェックして、データ件数がない場合に、画面上でのメッセージを表示するようにしています。flashと呼ばれる仕組みを使ってメッセージを代入しています。

 次は、このアクションに対応した表示部分のソースを読んでいきましょう。groups_controllerのindexメソッドに対応するビューは、「app/views/groups/index.html.erb」です。

01 <div class="search_cond_space">
02 <% form_tag({:action => 'index'}, :method => 'get') do -%>
03 <table class="search_cond_box">
04   <tr>
05     <th>グループ名・説明文</th>
06     <td>
07       <%= text_field_tag 'keyword' , params[:keyword], :size => 40 %><br/>
08       <%= check_box_tag 'yet_participation', 'true', params[:yet_participation] %>
09       まだ参加していないグループのみ表示
10     </td>
11   </tr>
12 
 〜〜中略〜〜
13 
14 </table>
15 <div class="submit"><%= submit_tag '検索' %></div>
16 <% end %>
17 </div><!-- search_cond_space -->
18
19 <div class="search_result_space">
20 <%= render :partial => 'groups/group_list', :locals => { :pages => @pages, :groups => @groups, :user_id => session[:user_id], :format_type => @format_type } -%>
21 </div><!-- search_result_space -->
   app/views/groups/index.html.erb

 画面全体のレイアウトについては、「app/views/layout/layout.html.erb」で記述されています。レイアウトにそのファイルを使う指定は、「app/controllers/application.rb」の中で指定しています。

 index.html.erbは、検索条件を表示する前半部分と、検索結果を表示する後半部分に大きく分けることができます。

 検索条件のフォームの指定(2行目)では、呼び出すアクションを自分自身のindexメソッドにして、HTTPメソッドとしてGETを使うように指定しています。この画面での検索は、サーバ状態に副作用をもたらさないためGETにすることはREST思想にかなっています。

 検索結果を表示する部分(19〜21行目)では、Railsのpartial機能を使っています。partial機能を使うと、画面部品の共通化ができます。ここでは、グループの一覧表示部分をほかの画面でも使っているため、共通化されています。

 どの共通部品を使うのかは、「:partial =>」で指定している部分になります。今回は、「app/views/groups/_group_list.html.erb」を指定しています。共通化された画面部品のファイル名の先頭には、_(アンダースコア)を付ける規約になっています。「:locals =>」で指定することで、部品側で使える変数を設定しています。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。