プロジェクト

全般

プロフィール

GuideForProject » 履歴 » バージョン 4

Mitsuyoshi Yoshida, 2011/06/26 00:48

1 1 Mitsuyoshi Yoshida
h1. プロジェクトで利用可能にする
2
3
プラグインをプロジェクトごとに使用できるようするためにはプロジェクトモジュールとしての登録とプロジェクトメニューへの項目の追加が必要となります。
4
5
6
h2. モジュールと permission の設定
7
8
モジュールの登録ではモジュール名とアクションごとの実行する権限(permission)を指定します。
9
10
|_. 権限       |_. アクション       |
11
| データの表示 | index, view        |
12
| データの管理 | new, edit, destory |
13
14
権限の指定は init.rb の Redmine::Plugin::register メソッドで行います。次の記述をブロック内に追加してください。
15
16
<pre><code class="ruby">
17
  project_module :standard do
18
    permission :view_foos, :foos => [:index, :show]
19
    permission :manage_foos, :foos => [:new, :edit, :destroy],
20
               :require => :member
21
  end
22
</code></pre>
23
24
*project_module* メソッドの引数でモジュール名(standard)を指定し、ブロック内で *permission* メソッドを呼び出して権限の指定をしています。
25
26
permission メソッドの書式は次の形です。
27
28
<pre><code class="ruby">
29
permission(name, hash, options={})
30
</code></pre>
31
32
第一引数で権限の名前を指定します。
33
第二引数にはコントローラ名をキー、アクション名の配列を値としたハッシュを渡します。サンプルではコントローラは一つしかありませんが、複数あることもあるので、ハッシュで指定できるようになっています。
34
第三引数はオプションです。
35
36
Rails では次のようなスタイルがよくとられるので慣れておきましょう。
37 2 Mitsuyoshi Yoshida
38 1 Mitsuyoshi Yoshida
* メソッドのオプション的な指定は最後の引数でシンボル名をキーとしたハッシュを使ってまとめて渡す
39 3 Mitsuyoshi Yoshida
* ハッシュが一つのペアしか持たなかったり、最後の引数などで括弧 {} が省略できる場合は省略する
40 1 Mitsuyoshi Yoshida
41
このオプションの *:require* の指定を使って、データ管理の権限(:manage_foos)ではプロジェクトメンバー以外の Non member や Anonymous(ログインしていない人)では使えないようにしています。
42
43
それでは Redmine を起動して、プラグインをプロジェクトで使用できるようにしましょう。
44
45
まず、管理メニューにあるロールと権限の *権限レポート* でチェックをいれて権限を与えます。
46
47
!permission.png!
48
49
次にプラグインを使いたいプロジェクトの設定で Standard モジュールを有効にします。
50
51
!module_add.png!
52
53
このときの表示は指定したモジュール名などがほぼそのまま表示されているだけですが、これを日本語に変更する方法は[[GuideI18n|国際化]]のところで説明します。
54
55
56
h2. プラグインメニューへの追加
57
58
プロジェクトでモジュールを有効にしてもまだ何も変わりません。実際にこのプラグインを使えるようにするためにはプロジェクトメニューに項目を追加する必要があります。
59
プロジェクトメニューにはこのプラグインで最初に表示させたいページに対応するアクションを追加します。サンプルでは foos コントロールの index アクションとなります。
60
61
メニュー項目の追加も init.rb で行います。先ほどの記述の後に以下を加えます。
62
63
<pre><code class="ruby">
64
  menu :project_menu, :standard, { :controller => 'foos', :action => 'index' }
65
</code></pre>
66
67
メニューの項目の追加は *menu* メソッドを使います。
68
69
<pre><code class="ruby">
70
menu(menu, item, url, options={})
71
</code></pre>
72
73
第 1 引数はメニューの名前です。ここではプロジェクトメニューを指定します。指定できるメニューは [[GuideSampleSpec|サンプル仕様]] で説明した 4 つです。
74
75
|_. メニュー               |_. メニュー名      |
76
| トップメニュー	   | :top_menu         |
77
| アカウントメニュー	   | :account_menu     |
78
| プロジェクトメニュー	   | :project_menu     |
79
| アプリケーションメニュー | :application_menu |
80
81
第 2 引数はメニューの項目名です。
82
第 3 引数はメニューをクリックしたときのリンク先の URL を指定します。
83
第 4 引数はオプションでここでは省略しています。
84
85
86
h2. Rails での URL の指定方法
87
88
前節のメニューで行った URL の指定方法は *link_to* などでの他の Rails のリンクの指定方法と同じです。
89
URL の指定方法についてもう少し詳しく説明しましょう。
90
91
URL として文字列を指定すると単純にその文字列が url として使用されますが、ハッシュで指定するとそれを元に URL を生成します。
92
93
指定するキーはコントローラ名(:controller)、アクション名(:action)と ID名(:id) で、そのキーの値を使って次のようなアドレスとなります。
94
95
<pre>
96
サーバアドレス/コントローラ名/アクション名/ID名
97
</pre>
98
99
ID 名は省略可能で省略されると ID 名の部分はなくなります。ただし、ここで省略しているのはプロジェクトメニューから呼ばれると自動的に ID 名はプロジェクトの識別名になるためです。サンプルのアドレスは以下のようになります。(プロジェクトの識別名は demo にしています)
100
101
<pre>
102
http://127.0.0.1:3000/foos/index/demo
103
</pre>
104
105
このアドレスの指定によりコントロールのアクションが実行されることになります。この場合は FoosController の index メソッドが呼ばれます。
106 4 Mitsuyoshi Yoshida
ID は *params* というハッシュクラスの変数に格納されてます。params は $ マークは付いてませんが、グローバル変数のようなものだと考えてください。
107 1 Mitsuyoshi Yoshida
108
プロジェクトの識別名は :id を使わずに :project_id に入れて、config/routes.rb でアドレスの表示を変える方法もあります。サンプルでは :id を使った方が簡単だと思ったのでこちらの方法をとっています。
109
110
111
h2. index ページの表示
112
113
Redmine を再起動してモジュールを追加したプロジェクトを開いてみましょう。プロジェクトメニューに *Standard* が追加されています。
114
115
!sample_proj_menu.png!
116
117
このメニューをクリックして下さい。 index.html.erb の内容のページが表示されます。
118
119
!index_no_project.png!
120
121
コントローラの index メソッドの中にはまだ何も書いていません。それにもかかわらず、 index ページが表示されています。これはコントローラのアクションが実行されるとアクション名のメソッドが実行され、デフォルトの状態ではアクション名に対応する views のファイルが表示されるためです。
122
スケルトンとして生成されたファイルは index.html.erb ですが、検索されるファイルはアクション名の後は .rhtml, .erb のような Erb の html を表す拡張子であれば何でもかまいません。
123
124
125
h2. @project の設定
126
127
ただし、表示されたページよく見ると何か変なことに気づくと思います。これは他のプロジェクトメニューと違いプロジェクトが開かれていないためです。このページをプロジェクトに属するものするためには FoosController クラスのインスタンス変数 *@project* に値を設定する必要があります。
128
129
FoosController クラスの末尾に次のような @project を設定する *find_project* メソッドの定義を追加します。外から呼ばれることはありませんので、private メソッドにしています。
130
<pre><code class="ruby">
131
class FoosController < ApplicationController
132
  unloadable
133
    # :
134
private
135
  def find_project
136
    @project = Project.find(params[:id])
137
  rescue ActiveRecord::RecordNotFound
138
    render_404
139
  end
140
end
141
</code></pre>
142
143
params[:id] にはプロジェクトの識別名が入っています。 
144
Project はプロジェクト用のモデルクラスです。  *find* メソッドは引数にプロジェクト識別名を渡すと、データベースから識別名が一致するプロジェクトを探し、Project のオブジェクトを返すクラスメソッドです。
145
146
Project クラスも ActiveRecord::Base クラスを継承して作成されており、データがみつからないと *ActiveRecord::RecordNotFound* の例外が発生します。コントローラ内で例外が発生すると通常の http サーバの場合 Internal Error のページになってしまいます。(WEBrick では詳細なエラー情報の画面になります。)
147
この例外をキャッチして *render_404* を実行しています。 これはファイルが見つかりませんといった http の 404 エラーのページを表示するメソッドです。
148
149
定義した find_project メソッドを index メソッドの中で呼び出せばプロジェクト内のページとして表示されます。
150
151
152
h2. before_filter
153
154
アクションは index だけではありません。他のアクションのメソッドでも同様に find_project を呼び出す必要があります。じゃ、 index の find_project をコピーして、他のメソッドにもペーストしていって ... と思った人はちょっと待ってください。 それでは同じことを何度も書く羽目になります。 Rails には DRY(Don't Repeat Yourself) という繰り返し禁止の方針がありました。何か繰り返しを避ける方法があるはずです。
155
156
実際、避ける方法は用意されています。それは *before_filter* です。これでメソッドを指定するとそのメソッドはアクションのメソッドの前に呼ばれるようになります。
157
こちらはコントローラクラスの先頭の方に追加します。
158
159
<pre><code class="ruby">
160
class FoosController < ApplicationController
161
  unloadable
162
  before_filter :find_project
163
    # :
164
</code></pre>
165
166
167
h2. authorize
168
169
before_filter はカンマで区切って複数のメソッドを指定することが出来ます。もう一つ追加してみましょう。
170
<pre><code class="ruby">
171
class FoosController < ApplicationController
172
  unloadable
173
  before_filter :find_project, :authorize
174
    # :
175
</code></pre>
176
177
追加した *authorize* はページを開いた時にログインしていない場合はログインのページ行く Redmine のメソッドです。通常、プロジェクトメニューから開かれるので、ログインしていることが多いと思いますが、ブラウザで前に開いていたページをもう一度開くといった設定がしてある場合などでは直接ページが指定されることもあります。そういったときにもちゃんとログインできるようにすべてのアクションの前に実行しておく必要があります。
178
179
権限の設定で index や show では設定によってはログインしてなくても、表示できる場合があるのではと疑問を持った方もいると思いますが、そういう場合も Redmine がログインしないように上手く処理してくれます。
180
181
権限の判定には現在のプロジェクトの情報が必要となります。before_filter は追加した順に実行されますので必ず find_project, authorize の順で記述して下さい。
182
183
ここまで設定して、もう一度 [Standard] のメニューを選択してみてください。今度はプロジェクトのページとして開かれているはずです。
184
185
!index_no_tab.png!
186
187
まだ、少し変なところがあります。メニュー項目が選択状態になっていませんね。これを解決するにはコントローラ内で *menu_item* を使ってメニュー項目を指定します。
188
189
<pre><code class="ruby">
190
  menu_item :メニュー項目のシンボル
191
</code></pre>
192
193
このメソッドで指定しなくてもメニュー項目が選択状態になることがあります。実はどうしたらそうなるのかは私もよく分かりません。とりあえず、選択状態にならないときはこのメソッドで指定してみてください。
194
195
これまでの記述を追加したコントローラのファイルの中身は次のようになります。
196
197
<pre><code class="ruby">
198
class FoosController < ApplicationController
199
  unloadable
200
  menu_item :standard
201
  before_filter :find_project, :authorize
202
203
204
  def index
205
  end
206
207
208
  def new
209
  end
210
211
212
  def show
213
  end
214
215
216
  def edit
217
  end
218
219
private
220
  def find_project
221
    @project = Project.find(params[:id])
222
  rescue ActiveRecord::RecordNotFound
223
    render_404
224
  end
225
end
226
</code></pre>
227
228
これでプロジェクトメニューにきちんと登録できるようになりました。
229
230
!index_tab.png!
231
232
----
233
234
| [[プラグイン開発ガイド|^]] | [[GuideControlSkelton|<<]] | [[GuideI18n|>>]] |