プラグイン チュートリアル

Version 9 (Haru Iida, 05/28/2009 04:41 pm)

1 1 Haru Iida
www.redmine.orgの"Plugin Turorial":http://www.redmine.org/wiki/redmine/Plugin_Tutorial を和訳してみます。
2 1 Haru Iida
3 1 Haru Iida
h1. プラグイン チュートリアル
4 1 Haru Iida
5 6 Haru Iida
注意: このチュートリアルはRedmineの開発リビジョン @r1786@ 以上を対象にしています。
6 1 Haru Iida
7 1 Haru Iida
{{toc}}
8 1 Haru Iida
9 1 Haru Iida
h2. 新しいプラグインを作る。
10 1 Haru Iida
11 1 Haru Iida
プラグインの新規作成はRedmineのプラグインジェネレータを使用して行うことができます。
12 1 Haru Iida
ジェネレータのコマンドは以下です。:
13 1 Haru Iida
14 1 Haru Iida
<pre>ruby script/generate redmine_plugin <plugin_name></pre>
15 1 Haru Iida
16 1 Haru Iida
コマンドプロンプトを開き "cd" であなたがredmineをインストールしたディレクトリに移動し、以下のコマンドを実行してみましょう。:
17 1 Haru Iida
18 1 Haru Iida
  % ruby script/generate redmine_plugin Polls
19 1 Haru Iida
20 2 Haru Iida
@vendor/plugins/redmine_polls@ の下に以下のようなファイルとディレクトリが作られます:
21 1 Haru Iida
22 1 Haru Iida
<pre>
23 1 Haru Iida
      create  vendor/plugins/redmine_polls/app/controllers
24 1 Haru Iida
      create  vendor/plugins/redmine_polls/app/helpers
25 1 Haru Iida
      create  vendor/plugins/redmine_polls/app/models
26 1 Haru Iida
      create  vendor/plugins/redmine_polls/app/views
27 1 Haru Iida
      create  vendor/plugins/redmine_polls/db/migrate
28 1 Haru Iida
      create  vendor/plugins/redmine_polls/lib/tasks
29 1 Haru Iida
      create  vendor/plugins/redmine_polls/assets/images
30 1 Haru Iida
      create  vendor/plugins/redmine_polls/assets/javascripts
31 1 Haru Iida
      create  vendor/plugins/redmine_polls/assets/stylesheets
32 1 Haru Iida
      create  vendor/plugins/redmine_polls/lang
33 1 Haru Iida
      create  vendor/plugins/redmine_polls/README
34 1 Haru Iida
      create  vendor/plugins/redmine_polls/init.rb
35 1 Haru Iida
      create  vendor/plugins/redmine_polls/lang/en.yml
36 1 Haru Iida
</pre>
37 1 Haru Iida
38 2 Haru Iida
@vendor/plugins/redmine_polls/init.rb@ を編集してあなたのプラグインの情報を書き込んでください。(name, author, description および version):
39 1 Haru Iida
40 1 Haru Iida
<pre><code class="ruby">
41 1 Haru Iida
require 'redmine'
42 1 Haru Iida
43 1 Haru Iida
Redmine::Plugin.register :redmine_polls do
44 1 Haru Iida
  name 'Polls plugin'
45 1 Haru Iida
  author 'John Smith'
46 1 Haru Iida
  description 'A plugin for managing polls'
47 1 Haru Iida
  version '0.0.1'
48 1 Haru Iida
end
49 1 Haru Iida
</code></pre>
50 1 Haru Iida
51 2 Haru Iida
そしてRedmineを起動し、ブラウザから次のアドレスを入力します。http://localhost:3000/admin/info.
52 2 Haru Iida
ログイン後、あなたのプラグインがプラグイン一覧に加わっていることが確認できます。
53 1 Haru Iida
54 4 Haru Iida
!plugins_list1.png!
55 1 Haru Iida
56 5 Haru Iida
h2. モデルを作る
57 1 Haru Iida
58 5 Haru Iida
それではこのプラグインのモデルとして Poll を作ってみましょう。:
59 1 Haru Iida
60 1 Haru Iida
  ruby script/generate redmine_plugin_model polls poll question:string yes:integer no:integer
61 1 Haru Iida
62 5 Haru Iida
このコマンドで Poll モデルおよびPollモデルに対応したマイグレーションファイルが作成されます。
63 5 Haru Iida
(訳注:マイグレーションファイルとは、RedmineのDBにこのモデル用のテーブルを作成するためのスクリプトファイルです)
64 1 Haru Iida
65 5 Haru Iida
ここで注意が必要です。timestamped migrationは今のRedmineプラグインエンジンではサポートされていません。ファイル名についているタイムスタンプを"001", "002"のような名前に変更してください。
66 1 Haru Iida
67 5 Haru Iida
実際にデータベースへのマイグレーションを行うためには以下のコマンドを実行します。:
68 1 Haru Iida
69 1 Haru Iida
  rake db:migrate_plugins
70 1 Haru Iida
71 5 Haru Iida
すべてのプラグインはそれぞれに自身のマイグレーションファイルを持っています。
72 1 Haru Iida
73 6 Haru Iida
それではconsoleスクリプトからPollのデータを追加してみましょう。ちゃんとテーブルが作られていることを確認できます。consoleを使用すると対話的にRedmineを動かして確認できます。また、遊びながらいろいろな情報を得ることができます。それでは2つのPollオブジェクトを作ります。
74 1 Haru Iida
75 1 Haru Iida
<pre>
76 1 Haru Iida
script/console
77 1 Haru Iida
>> Poll.create(:question => "Can you see this poll ?")
78 1 Haru Iida
>> Poll.create(:question => "And can you see this other poll ?")
79 1 Haru Iida
>> exit
80 1 Haru Iida
</pre>
81 1 Haru Iida
82 6 Haru Iida
プラグインディレクトリの @vendor/plugins/redmine_polls/app/models/poll.rb@ を編集して #vote メソッドを追加しましょう。このメソッドはコントローラから実行されるものです。:
83 1 Haru Iida
84 1 Haru Iida
<pre><code class="ruby">
85 1 Haru Iida
class Poll < ActiveRecord::Base
86 1 Haru Iida
  def vote(answer)
87 1 Haru Iida
    increment(answer == 'yes' ? :yes : :no)
88 1 Haru Iida
  end
89 1 Haru Iida
end
90 1 Haru Iida
</code></pre>
91 1 Haru Iida
92 7 Haru Iida
h2. コントローラを作成する。
93 1 Haru Iida
94 7 Haru Iida
この段階ではまだこのプラグインは何もすることができません。このプラグインにコントローラを追加してみましょう。コントローラの作成にはプラグインコントローラジェネレータを使用できます。文法は以下です。:
95 1 Haru Iida
96 1 Haru Iida
<pre>ruby script/generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]</pre>
97 1 Haru Iida
98 7 Haru Iida
ではコマンドプロンプトから以下のように打ってみましょう。:
99 1 Haru Iida
100 1 Haru Iida
<pre>
101 1 Haru Iida
% ruby script/generate redmine_plugin_controller Polls polls index vote
102 1 Haru Iida
      exists  app/controllers/
103 1 Haru Iida
      exists  app/helpers/
104 1 Haru Iida
      create  app/views/polls
105 1 Haru Iida
      create  test/functional/
106 1 Haru Iida
      create  app/controllers/polls_controller.rb
107 1 Haru Iida
      create  test/functional/polls_controller_test.rb
108 1 Haru Iida
      create  app/helpers/polls_helper.rb
109 1 Haru Iida
      create  app/views/polls/index.html.erb
110 1 Haru Iida
      create  app/views/polls/vote.html.erb
111 1 Haru Iida
</pre>
112 1 Haru Iida
113 7 Haru Iida
コントローラ @PollsController@ と2つのアクション (@#index@ and @#vote@) が作成されます。
114 1 Haru Iida
115 7 Haru Iida
@vendor/plugins/redmine_polls/app/controllers/polls_controller.rb@ を編集して 2つのアクションを実装します。
116 1 Haru Iida
117 1 Haru Iida
<pre><code class="ruby">
118 1 Haru Iida
class PollsController < ApplicationController
119 1 Haru Iida
  unloadable
120 1 Haru Iida
121 1 Haru Iida
  def index
122 1 Haru Iida
    @polls = Poll.find(:all)
123 1 Haru Iida
  end
124 1 Haru Iida
125 1 Haru Iida
  def vote
126 1 Haru Iida
    poll = Poll.find(params[:id])
127 1 Haru Iida
    poll.vote(params[:answer])
128 1 Haru Iida
    if poll.save
129 1 Haru Iida
      flash[:notice] = 'Vote saved.'
130 1 Haru Iida
      redirect_to :action => 'index'
131 1 Haru Iida
    end
132 1 Haru Iida
  end
133 1 Haru Iida
end
134 1 Haru Iida
</code></pre>
135 1 Haru Iida
136 8 Haru Iida
そして @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ を編集すると先ほど作成した2つのpollを表示できます。:
137 1 Haru Iida
138 1 Haru Iida
139 1 Haru Iida
<pre>
140 1 Haru Iida
<h2>Polls</h2>
141 1 Haru Iida
142 1 Haru Iida
<% @polls.each do |poll| %>
143 1 Haru Iida
  <p>
144 1 Haru Iida
  <%= poll[:question] %>?
145 1 Haru Iida
  <%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes'}, :method => :post %> (<%= poll[:yes] %>) /
146 1 Haru Iida
  <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no'}, :method => :post %> (<%= poll[:no] %>)
147 1 Haru Iida
  </p>
148 1 Haru Iida
<% end %>
149 1 Haru Iida
</pre>
150 1 Haru Iida
151 8 Haru Iida
@vendor/plugins/redmine_polls/app/views/polls/vote.html.erb@ は対応するactionから使われることがないので削除してよいです。
152 1 Haru Iida
153 8 Haru Iida
さあ、Redmineを再起動してブラウザから http://localhost:3000/polls にアクセスしましょう。
154 8 Haru Iida
2つのpollが確認でき、それらに投票することができるでしょう。:
155 1 Haru Iida
156 8 Haru Iida
!pools1.png!
157 1 Haru Iida
158 1 Haru Iida
Note that poll results are reset on each request if you don't run the application in production mode, since our poll "model" is stored in a class variable in this example.
159 1 Haru Iida
160 9 Haru Iida
h2. メニューを拡張する。
161 1 Haru Iida
162 9 Haru Iida
コントローラは動くようになりましたが、このままではユーザはURLを知らない限り投票画面を見ることができません。RedmineのプラグインAPIを使用するとメニューを拡張できます。アプリケーションメニューに新しい項目を追加してみましょう。
163 1 Haru Iida
164 9 Haru Iida
h3. アプリケーションメニューを拡張する。
165 1 Haru Iida
166 9 Haru Iida
@vendor/plugins/redmine_polls/init.rb@ を編集してplugin registration blockの最後に以下の行を追加してください。:
167 1 Haru Iida
168 1 Haru Iida
<pre><code class="ruby">
169 1 Haru Iida
Redmine::Plugin.register :redmine_polls do
170 1 Haru Iida
  [...]
171 1 Haru Iida
  
172 1 Haru Iida
  menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls'
173 1 Haru Iida
end
174 1 Haru Iida
</code></pre>
175 1 Haru Iida
176 9 Haru Iida
文法は以下です。:
177 1 Haru Iida
178 1 Haru Iida
  menu(menu_name, item_name, url, options={})
179 1 Haru Iida
180 9 Haru Iida
拡張できるメニューは4種類です。:
181 1 Haru Iida
182 9 Haru Iida
* @:top_menu@ - 最上部の左側のメニュー。
183 9 Haru Iida
* @:account_menu@ - 最上部の右側のメニュー。ログイン/ログアウトがある。
184 9 Haru Iida
* @:application_menu@ - プロジェクトの外でのメインメニュー。
185 9 Haru Iida
* @:project_menu@ - プロジェクト内でのメインメニュー。
186 1 Haru Iida
187 9 Haru Iida
以下のオプションが使えます。:
188 1 Haru Iida
189 9 Haru Iida
* @:param@ - プロジェクトIDを渡すのに用いられる変数のキー。 (デフォルトは @:id@)
190 9 Haru Iida
* @:if@ - メニュー項目のレンダリング前に呼ばれるProc。メニュー項目はこのProcの戻りがtrueの場合にのみ表示される。
191 9 Haru Iida
* @:caption@ - メニューのキャプション。以下が使えます。:
192 1 Haru Iida
193 9 Haru Iida
  * ローカライズ文字列用シンボル
194 9 Haru Iida
  * 文字列
195 9 Haru Iida
  * projectを引数としたProc
196 1 Haru Iida
197 9 Haru Iida
* @:before@, @:after@ - メニューを挿入する場所の指定 (例 @:after => :activity@ 訳注:「活動」ページの後ろに挿入される)
198 9 Haru Iida
* @:last@ - trueに設定するとメニューの最後に追加される。 (例 @:last => true@)
199 9 Haru Iida
* @:html_options@ - html オプションのHash。メニュー表示時の @link_to@ に渡される。訳注: @link_to@はRailsのAPI
200 1 Haru Iida
201 9 Haru Iida
今回の例ではメニュー項目をアプリケーションメニューに追加します。アプリケーションメニューはデフォルトでは空です。
202 9 Haru Iida
Redmineを再起動して http://localhost:3000 にアクセスしてみましょう。:
203 1 Haru Iida
204 9 Haru Iida
!application_menu.png!
205 1 Haru Iida
206 9 Haru Iida
ようこそ画面のPollsタブをクリックして投票画面に行けるはずです。
207 1 Haru Iida
208 1 Haru Iida
h3. Extending the project menu
209 1 Haru Iida
210 1 Haru Iida
Now, let's consider that the polls are defined at project level (even if it's not the case in our example poll model). So we would like to add the Polls tab to the project menu instead.
211 1 Haru Iida
Open @init.rb@ and replace the line that was added just before with these 2 lines:
212 1 Haru Iida
213 1 Haru Iida
<pre><code class="ruby">
214 1 Haru Iida
Redmine::Plugin.register :redmine_polls do
215 1 Haru Iida
  [...]
216 1 Haru Iida
217 1 Haru Iida
  permission :polls, {:polls => [:index, :vote]}, :public => true
218 1 Haru Iida
  menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id
219 1 Haru Iida
end
220 1 Haru Iida
</code></pre>
221 1 Haru Iida
222 1 Haru Iida
The second line adds our Polls tab to the project menu, just after the activity tab.
223 1 Haru Iida
The first line is required and declares that our 2 actions from @PollsController@ are public. We'll come back later to explain this with more details.
224 1 Haru Iida
225 1 Haru Iida
Restart the application again and go to one of your projects:
226 1 Haru Iida
227 1 Haru Iida
p=. !project_menu.png!
228 1 Haru Iida
229 1 Haru Iida
If you click the Polls tab, you should notice that the project menu is no longer displayed.
230 1 Haru Iida
To make the project menu visible, you have to initialize the controller's instance variable @@project@.
231 1 Haru Iida
232 1 Haru Iida
Edit your PollsController to do so:
233 1 Haru Iida
234 1 Haru Iida
<pre><code class="ruby">
235 1 Haru Iida
def index
236 1 Haru Iida
  @project = Project.find(params[:project_id])
237 1 Haru Iida
  @polls = Poll.find(:all) # @project.polls
238 1 Haru Iida
end
239 1 Haru Iida
</code></pre>
240 1 Haru Iida
241 1 Haru Iida
The project id is available in the @:project_id@ param because of the @:param => :project_id@ option in the menu item declaration above.
242 1 Haru Iida
243 1 Haru Iida
Now, you should see the project menu when viewing the polls:
244 1 Haru Iida
245 1 Haru Iida
p=. !project_menu_pools.png!
246 1 Haru Iida
247 1 Haru Iida
h2. Adding new permissions
248 1 Haru Iida
249 1 Haru Iida
For now, anyone can vote for polls. Let's make it more configurable by changing the permission declaration.
250 1 Haru Iida
We're going to declare 2 project based permissions, one for viewing the polls and an other one for voting. These permissions are no longer public (@:public => true@ option is removed).
251 1 Haru Iida
252 1 Haru Iida
Edit @vendor/plugins/redmine_polls/init.rb@ to replace the previous permission declaration with these 2 lines:
253 1 Haru Iida
254 1 Haru Iida
<pre><code class="ruby">
255 1 Haru Iida
256 1 Haru Iida
  permission :view_polls, :polls => :index
257 1 Haru Iida
  permission :vote_polls, :polls => :vote
258 1 Haru Iida
</code></pre>
259 1 Haru Iida
260 1 Haru Iida
261 1 Haru Iida
Restart the application and go to http://localhost:3000/roles/report:
262 1 Haru Iida
263 1 Haru Iida
p=. !permissions1.png!
264 1 Haru Iida
265 1 Haru Iida
You're now able to give these permissions to your existing roles.
266 1 Haru Iida
267 1 Haru Iida
Of course, some code needs to be added to the PollsController so that actions are actually protected according to the permissions of the current user.
268 1 Haru Iida
For this, we just need to append the @:authorize@ filter and make sure that the @project instance variable is properly set before calling this filter.
269 1 Haru Iida
270 1 Haru Iida
Here is how it would look like for the @#index@ action:
271 1 Haru Iida
272 1 Haru Iida
<pre><code class="ruby">
273 1 Haru Iida
class PollsController < ApplicationController
274 1 Haru Iida
  unloadable
275 1 Haru Iida
  
276 1 Haru Iida
  before_filter :find_project, :authorize, :only => :index
277 1 Haru Iida
278 1 Haru Iida
  [...]
279 1 Haru Iida
  
280 1 Haru Iida
  def index
281 1 Haru Iida
    @polls = Poll.find(:all) # @project.polls
282 1 Haru Iida
  end
283 1 Haru Iida
284 1 Haru Iida
  [...]
285 1 Haru Iida
  
286 1 Haru Iida
  private
287 1 Haru Iida
  
288 1 Haru Iida
  def find_project
289 1 Haru Iida
    # @project variable must be set before calling the authorize filter
290 1 Haru Iida
    @project = Project.find(params[:project_id])
291 1 Haru Iida
  end
292 1 Haru Iida
end
293 1 Haru Iida
</code></pre>
294 1 Haru Iida
295 1 Haru Iida
Retrieving the current project before the @#vote@ action could be done using a similar way.
296 1 Haru Iida
After this, viewing and voting polls will be only available to admin users or users that have the appropriate role on the project.
297 1 Haru Iida
298 1 Haru Iida
h2. Creating a project module
299 1 Haru Iida
300 1 Haru Iida
For now, the poll functionality is added to all your projects. But you way want to enable polls for some projects only.
301 1 Haru Iida
So, let's create a 'Polls' project module. This is done by wrapping the permissions declaration inside a call to @#project_module@.
302 1 Haru Iida
303 1 Haru Iida
Edit @init.rb@ and change the permissions declaration:
304 1 Haru Iida
305 1 Haru Iida
<pre><code class="ruby">
306 1 Haru Iida
  project_module :polls do
307 1 Haru Iida
    permission :view_polls, :polls => :index
308 1 Haru Iida
    permission :vote_polls, :polls => :vote
309 1 Haru Iida
  end
310 1 Haru Iida
</code></pre>
311 1 Haru Iida
312 1 Haru Iida
Restart the application and go to one of your project settings.
313 1 Haru Iida
Click on the Modules tab. You should see the Polls module at the end of the modules list (disabled by default):
314 1 Haru Iida
315 1 Haru Iida
p=. !modules.png!
316 1 Haru Iida
317 1 Haru Iida
You can now enable/disable polls at project level.
318 1 Haru Iida
319 1 Haru Iida
h2. Improving the plugin views
320 1 Haru Iida
321 1 Haru Iida
h3. Adding stylesheets
322 1 Haru Iida
323 1 Haru Iida
Let's start by adding a stylesheet to our plugin views.
324 1 Haru Iida
Create a file named @voting.css@ in the @vendor/plugins/redmine_polls/assets/stylesheets@ directory:
325 1 Haru Iida
326 1 Haru Iida
<pre>
327 1 Haru Iida
a.vote { font-size: 120%; }
328 1 Haru Iida
a.vote.yes { color: green; }
329 1 Haru Iida
a.vote.no  { color: red; }
330 1 Haru Iida
</pre>
331 1 Haru Iida
332 1 Haru Iida
When starting the application, plugin assets are automatically copied to @public/plugin_assets/redmine_polls/@ by Rails Engines to make them available through your web server. So any change to your plugin stylesheets or javascripts needs an application restart.
333 1 Haru Iida
334 1 Haru Iida
Then, append the following lines at the end of @vendor/plugins/redmine_polls/app/views/polls/index.html.erb@ so that your stylesheet get included in the page header by Redmine:
335 1 Haru Iida
336 1 Haru Iida
<pre>
337 1 Haru Iida
<% content_for :header_tags do %>
338 1 Haru Iida
    <%= stylesheet_link_tag 'voting', :plugin => 'redmine_polls' %>
339 1 Haru Iida
<% end %>
340 1 Haru Iida
</pre>
341 1 Haru Iida
342 1 Haru Iida
Note that the @:plugin => 'redmine_polls'@ option is required when calling the @stylesheet_link_tag@ helper.
343 1 Haru Iida
344 1 Haru Iida
Javascripts can be included in plugin views using the @javascript_include_tag@ helper in the same way.
345 1 Haru Iida
346 1 Haru Iida
h3. Setting page title
347 1 Haru Iida
348 1 Haru Iida
You can set the HTML title from inside your views by using the @html_title@ helper.
349 1 Haru Iida
Example:
350 1 Haru Iida
351 1 Haru Iida
  <% html_title "Polls" -%>