プロジェクト

全般

プロフィール

GuideIndexAction » 履歴 » バージョン 2

Mitsuyoshi Yoshida, 2011/06/26 01:08

1 1 Mitsuyoshi Yoshida
h1. 一覧表示 アクション
2
3
サンプルの各アクションを作っていきましょう。
4
最初にプラグインのトップページである一覧表示を表示する index アクションの実装を行います。
5
6
7
h2. ページ表示の流れ
8
9
ページを表示するまでの流れのイメージをシーケンス図風に書いてみます。
10
11
!sequence.png!
12
13
# ユーザのアクション(ページ指定)により Redmine は指定のコントローラを作成します。
14
** アクションの度にコントローラのオブジェクトが作成されます。このため *インスタンス変数(@)はそのアクション限りでしか使用できません* 。すなわち、index アクションで格納したインスタンス変数の値を show アクションで使うといったことは出来ません。
15
# Redmine は指定されたアクションのメソッドを実行します。
16
** コントローラ、アクション以外のパラメータは params 変数に格納されます。
17
# アクションメソッドの後、アクションに対応したページが作成されます。
18
** コントローラ内で html の埋め込みコードが評価されます。このため *コントローラからビューへのデータの受け渡しにはインスタンス変数* を使うことが出来ます。
19
# 生成したページをユーザに表示します。
20
21
22
23
h2. コントローラの実装
24
25
コントローラ(app/controller/foo_app/controllers/foos_controller.rb) の index メソッドを実装します。 index ではデータベース(foos テーブル)から現在のプロジェクトに一致するデータ(foo)のリストを取得します。
26
27
<pre><code class="ruby">
28
  def index
29
    @foos = Foo.find(:all, :conditions => ["project_id = #{@project.id} "])
30
  end
31
</code></pre>
32
33
モデルクラスの *Foo#find* のクラスメソッドにより、条件に一致するデータを取得して、 *@foos* のインスタンス変数に格納しています。
34
35
第一引数では :all 、 :first などのシンボルを指定します。
36
37
|_. シンボル |_. 説明 |_. 戻り値 |
38
| :all | 条件に一致したすべてのデータを取得 | モデルオブジェクトの配列 |
39
| :first | 条件に一致した最初のデータを取得 | モデルオブジェクト |
40
41
第二引数はハッシュを受け取るオプションです。ここで *:conditions* を使って条件を指定します。
42
foo には属するプロジェクトの識別のためにプロジェクトの ID 番号を格納する [[GuideModel|project_id]] のメンバを持っていました。これが現在のプロジェクトの id と一致するということを条件にしています。 index メソッドの前には必ず [[GuideForProject|find_project]] が呼ばれて、@project に現在のプロジェクトのオブジェクトが格納されています。
43
44
実は :conditions の指定は SQL 形式での指定となるので、けっこう複雑です。ただ、フィルタ機能などを付けなければ、実際にプラグインを作成される場合もこのまま書いてもらえば十分だと思います。
45
検索条件の指定方法は機会があればそのうち詳しく書きたいと思います。
46
47
h2. ビューの実装
48
49
次にビュー (app/views/foos/index.html.erb) を実装します。
50
51
コントローラで設定した @foos はそのままビューでも使用できます。これにモデルのオブジェクトとしてレコードの情報が配列で入っているので、 html のテーブルを使って一覧表示します。
52
53
54
h3. データが空の場合の対策
55
56
データは空の場合があります。最初に @foos が空かどうかチェックして、空の場合はその内容のエラーメッセージを表示する必要があります。
57
58
<pre><code class="rhtml">
59
<% if (@foos.blank?) %>
60
  <p class="nodata"><%= l(:label_no_data) %></p>
61
<% else %>
62
   データのテーブル
63
<% end %>
64
</code></pre>
65
66
空のチェックには *blank?* のメソッドを使用しています。 empty? メソッドではオブジェクトが nil の場合例外が発生してしまいますが、 blank? であれば、 nil でもエラーとなりません。配列や文字列が空かチェックする場合は基本的にこちらを使う方がいいでしょう。
67
エラーメッセージ :label_no_data は Redmine で定義されているメッセージで、 class で指定している nodata も Redmine で定義されている CSS のクラスです。これらを使うことにより、 チケットのような Redmine の他のページと同じスタイルで表示できるようになります。
68
69
h3. テーブルの作成
70
71
@foos が空でなければテーブルを作成します。テーブルに表示する要素は foo の *ID 番号(id)* と *題名(subject)* にします。
72
73
<pre><code class="rhtml">
74
<table class="list">
75
76
<thead><tr>  
77
<th>#</th> <th><%=h l(:field_subject) %></th>
78
</tr></thead>
79
80
<tbody>
81
<% @foos.each do |foo| %>
82
  <tr class="<%= cycle('odd', 'even') %>">
83
  <td><%= foo.id %></td>
84
  <td><%= link_to(foo.subject, {:action=> :show, :id => @project, :foo_id => foo.id} ) %></td>
85
</tr>
86
<% end %>
87
</tbody>
88
89
</table>
90
</code></pre>
91
92
まず、テーブルのヘッダ行を出力して後テーブルの各行を *@foos.each* でループをまわして作成しています。
93
94
テーブルの *list*, *odd*, *even* も Redmine で定義された CSS のクラスで Redmine にあわせたスタイルにすることが出来ます。 odd, even は行の色を一つおきに変えていくためのもので、 Rails の *cycle* メソッドでループをまわす度にクラスを切り替えています。
95
96
テーブルの各行には各データの ID 番号(foo.id)と題名(foo.subject)を表示しています。
97
題名は各データの詳細ページ(show)へのリンクにしています。このときプロジェクトの識別名を ID として、データの id を *:foo_id* のパラメータとして渡しています。こうすることによって show アクションでは params[:foo_id] でデータの id 番号を取得することができるようになります。
98
:id に渡しているのは現在のプロジェクトのオブジェクト(@project)ですが、 Redmine の方で @project.identifer を呼び出して、プロジェクトの識別名にしてくれます。
99
また、コントローラは省略しています。コントローラが省略された場合、現在のアクションと同じコントローラが指定されたことになります。
100
101
h3. new アクションのリンクを追加
102
103
一覧表示ページから新規作成ができるようにします。そのためには new アクションのリンクを追加する必要があります。
104
105
<pre><code class="rhtml">
106
<div class="contextual">
107
  <%= link_to_if_authorized(l(:label_foos_new), 
108
                            {:action => 'new', :id => @project}, 
109
                            :class => 'icon icon-add') %>
110
</div>
111
</code></pre>
112
113
new へのリンクは *contextual* のクラスで指定された div 中に書きます。これにより Redmine の他の文書やファイルのページのようにページの右上に表示することが出来ます。リンクを表示する位置は CSS のスタイルで決められているので、 記述する位置は index.html.erb ファイル中のどこに書いてもかまいません。
114
115
リンクは通常 Rails の link_to を使用しますが、ここでは Redmine の *link_to_if_authorized* メソッドを使用しています。こうしておくことによって new アクションの権限がユーザに無い場合にはリンクは表示されなくなります。
116
117 2 Mitsuyoshi Yoshida
また、リンクのクラスには *"icon icon-add"* を使用して、追加用のアイコンを表示しています。これについての詳しい説明は [[TipsUseIcon|プラグイン Tips]] を見てください。
118 1 Mitsuyoshi Yoshida
119
120
h2. 一覧表示ページ
121
122
それでは、 Redmine で一覧表示のページを表示してみましょう。
123
まだ、データが何もないので空データのメッセージが表示されています。
124
125
!action_index.png!
126
127
この章で作成した index.html.erb ファイルの全文は次のようになります。
128
129
<pre><code class="rhtml">
130
131
<div class="contextual">
132
  <%= link_to_if_authorized(l(:label_foos_new), 
133
                            {:action => 'new', :id => @project}, 
134
                            :class => 'icon icon-add') %>
135
</div>
136
137
<h2> <%=h l :label_standard %> </h2>
138
139
<% if (@foos.blank?) %>
140
  <p class="nodata"><%= l(:label_no_data) %></p>
141
<% else %>
142
143
<table class="list">
144
145
<thead><tr>  
146
<th>#</th> <th><%=h l(:field_subject) %></th>
147
</tr></thead>
148
149
<tbody>
150
<% @foos.each do |foo| %>
151
  <tr class="<%= cycle('odd', 'even') %>">
152
  <td><%= foo.id %></td>
153
  <td><%= link_to(foo.subject, {:action=> :show, :id => @project, :foo_id => foo.id} ) %></td>
154
</tr>
155
<% end %>
156
</tbody>
157
158
</table>
159
160
<% end %>
161
</code></pre>
162
163
164
---
165
166
| [[プラグイン開発ガイド|^]] | [[GuideI18n|<<]] | [[GuideNewAction|>>]] |