GuideIndexAction » 履歴 » バージョン 6
NAITOH Jun, 2013/04/14 21:28
RESTfulな実装に変更。
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 | 5 | NAITOH Jun | コントローラ(app/controllers/foos_controller.rb) の index メソッドを実装します。 index ではデータベース(foos テーブル)から現在のプロジェクトに一致するデータ(foo)のリストを取得します。 |
26 | 1 | Mitsuyoshi Yoshida | |
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 | 6 | NAITOH Jun | <pre><code class="erb"> |
59 | 1 | Mitsuyoshi Yoshida | <% if (@foos.blank?) %> |
60 | <p class="nodata"><%= l(:label_no_data) %></p> |
||
61 | <% else %> |
||
62 | データのテーブル |
||
63 | <% end %> |
||
64 | </code></pre> |
||
65 | |||
66 | 3 | Mitsuyoshi Yoshida | 空のチェックには Rails が Object クラスに追加している *blank?* のメソッドを使用しています。 empty? メソッドではオブジェクトが nil の場合例外が発生してしまいますが、 blank? であれば、 nil でもエラーとなりません。配列や文字列が空かチェックする場合は基本的にこちらを使う方がいいでしょう。 blank? の逆のメソッドで *any?* というのもあります。 |
67 | 1 | Mitsuyoshi Yoshida | エラーメッセージ :label_no_data は Redmine で定義されているメッセージで、 class で指定している nodata も Redmine で定義されている CSS のクラスです。これらを使うことにより、 チケットのような Redmine の他のページと同じスタイルで表示できるようになります。 |
68 | |||
69 | h3. テーブルの作成 |
||
70 | |||
71 | @foos が空でなければテーブルを作成します。テーブルに表示する要素は foo の *ID 番号(id)* と *題名(subject)* にします。 |
||
72 | |||
73 | 6 | NAITOH Jun | <pre><code class="erb"> |
74 | 1 | Mitsuyoshi Yoshida | <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 | 6 | NAITOH Jun | <td><%= link_to foo.subject, project_foo_path(@project, foo.id) %></td> |
85 | 1 | Mitsuyoshi Yoshida | </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 | 6 | NAITOH Jun | 題名は各データの詳細ページ(show)へのリンクにしています。 |
98 | show のルーティングは次のようになっていました。 |
||
99 | <pre> |
||
100 | project_foo GET /projects/:project_id/foos/:id(.:format) foos#show |
||
101 | </pre> |
||
102 | show アクションのパス *project_foo_path* (オプションのルート名 project_foo に _path をつけたもの) へ第一引数(:project_id)にプロジェクトの識別名、第2匹引数(:id)として、データの IDを渡しています。 |
||
103 | こうすることによって show アクションでは params[:id] でデータの id 番号を取得することができるようになります。 |
||
104 | |||
105 | 1 | Mitsuyoshi Yoshida | :project_id に渡しているのは現在のプロジェクトのオブジェクト(@project)ですが、 Redmine の方で @project.identifer を呼び出して、プロジェクトの識別名にしてくれます。 |
106 | |||
107 | 6 | NAITOH Jun | なお、次のようにハッシュを使った URL 指定もできますが、簡単に理解しやすいパスを使った URL 指定をなるべく使っていきます。 |
108 | <pre><code class="ruby"> |
||
109 | {:controller => 'foos', :action=> :show, :project_id => @project, :id => foo.id} |
||
110 | </code></pre> |
||
111 | |||
112 | 1 | Mitsuyoshi Yoshida | h3. new アクションのリンクを追加 |
113 | |||
114 | 一覧表示ページから新規作成ができるようにします。そのためには new アクションのリンクを追加する必要があります。 |
||
115 | |||
116 | 6 | NAITOH Jun | <pre><code class="erb"> |
117 | 1 | Mitsuyoshi Yoshida | <div class="contextual"> |
118 | <%= link_to_if_authorized(l(:label_foos_new), |
||
119 | 4 | Mitsuyoshi Yoshida | {:action => 'new', :project_id => @project}, |
120 | 1 | Mitsuyoshi Yoshida | :class => 'icon icon-add') %> |
121 | </div> |
||
122 | </code></pre> |
||
123 | |||
124 | new へのリンクは *contextual* のクラスで指定された div 中に書きます。これにより Redmine の他の文書やファイルのページのようにページの右上に表示することが出来ます。リンクを表示する位置は CSS のスタイルで決められているので、 記述する位置は index.html.erb ファイル中のどこに書いてもかまいません。 |
||
125 | |||
126 | リンクは通常 Rails の link_to を使用しますが、ここでは Redmine の *link_to_if_authorized* メソッドを使用しています。こうしておくことによって new アクションの権限がユーザに無い場合にはリンクは表示されなくなります。 |
||
127 | 6 | NAITOH Jun | なお、 link_to_if_authorized メッソドの URL 指定はパスに対応していないのでハッシュで指定しています。 |
128 | また、コントローラは省略しています。コントローラが省略された場合、現在のアクションと同じコントローラが指定されたことになります。 |
||
129 | 2 | Mitsuyoshi Yoshida | |
130 | 1 | Mitsuyoshi Yoshida | また、リンクのクラスには *"icon icon-add"* を使用して、追加用のアイコンを表示しています。これについての詳しい説明は [[TipsUseIcon|プラグイン Tips]] を見てください。 |
131 | |||
132 | |||
133 | h2. 一覧表示ページ |
||
134 | |||
135 | それでは、 Redmine で一覧表示のページを表示してみましょう。 |
||
136 | まだ、データが何もないので空データのメッセージが表示されています。 |
||
137 | |||
138 | !action_index.png! |
||
139 | |||
140 | この章で作成した index.html.erb ファイルの全文は次のようになります。 |
||
141 | |||
142 | 6 | NAITOH Jun | <pre><code class="erb"> |
143 | 1 | Mitsuyoshi Yoshida | |
144 | <div class="contextual"> |
||
145 | <%= link_to_if_authorized(l(:label_foos_new), |
||
146 | {:action => 'new', :project_id => @project}, |
||
147 | :class => 'icon icon-add') %> |
||
148 | </div> |
||
149 | |||
150 | <h2> <%=h l :label_standard %> </h2> |
||
151 | |||
152 | <% if (@foos.blank?) %> |
||
153 | <p class="nodata"><%= l(:label_no_data) %></p> |
||
154 | <% else %> |
||
155 | |||
156 | <table class="list"> |
||
157 | |||
158 | <thead><tr> |
||
159 | <th>#</th> <th><%=h l(:field_subject) %></th> |
||
160 | </tr></thead> |
||
161 | |||
162 | <tbody> |
||
163 | <% @foos.each do |foo| %> |
||
164 | <tr class="<%= cycle('odd', 'even') %>"> |
||
165 | <td><%= foo.id %></td> |
||
166 | 6 | NAITOH Jun | <td><%= link_to foo.subject, project_foo_path(@project, foo.id) %></td> |
167 | 1 | Mitsuyoshi Yoshida | </tr> |
168 | <% end %> |
||
169 | </tbody> |
||
170 | |||
171 | </table> |
||
172 | |||
173 | <% end %> |
||
174 | </code></pre> |
||
175 | |||
176 | |||
177 | --- |
||
178 | |||
179 | | [[プラグイン開発ガイド|^]] | [[GuideI18n|<<]] | [[GuideNewAction|>>]] | |