GuideForProject » 履歴 » リビジョン 3
リビジョン 2 (Mitsuyoshi Yoshida, 2011/06/26 00:42) → リビジョン 3/10 (Mitsuyoshi Yoshida, 2011/06/26 00:44)
h1. プロジェクトで利用可能にする プラグインをプロジェクトごとに使用できるようするためにはプロジェクトモジュールとしての登録とプロジェクトメニューへの項目の追加が必要となります。 h2. モジュールと permission の設定 モジュールの登録ではモジュール名とアクションごとの実行する権限(permission)を指定します。 |_. 権限 |_. アクション | | データの表示 | index, view | | データの管理 | new, edit, destory | 権限の指定は init.rb の Redmine::Plugin::register メソッドで行います。次の記述をブロック内に追加してください。 <pre><code class="ruby"> project_module :standard do permission :view_foos, :foos => [:index, :show] permission :manage_foos, :foos => [:new, :edit, :destroy], :require => :member end </code></pre> *project_module* メソッドの引数でモジュール名(standard)を指定し、ブロック内で *permission* メソッドを呼び出して権限の指定をしています。 permission メソッドの書式は次の形です。 <pre><code class="ruby"> permission(name, hash, options={}) </code></pre> 第一引数で権限の名前を指定します。 第二引数にはコントローラ名をキー、アクション名の配列を値としたハッシュを渡します。サンプルではコントローラは一つしかありませんが、複数あることもあるので、ハッシュで指定できるようになっています。 第三引数はオプションです。 Rails では次のようなスタイルがよくとられるので慣れておきましょう。 * メソッドのオプション的な指定は最後の引数でシンボル名をキーとしたハッシュを使ってまとめて渡す * ハッシュが一つのペアしか持たなかったり、最後の引数などで括弧 ハッシュが一つのペアしか持たないや最後の引数などで括弧 {} が省略できる場合は省略する このオプションの *:require* の指定を使って、データ管理の権限(:manage_foos)ではプロジェクトメンバー以外の Non member や Anonymous(ログインしていない人)では使えないようにしています。 それでは Redmine を起動して、プラグインをプロジェクトで使用できるようにしましょう。 まず、管理メニューにあるロールと権限の *権限レポート* でチェックをいれて権限を与えます。 !permission.png! 次にプラグインを使いたいプロジェクトの設定で Standard モジュールを有効にします。 !module_add.png! このときの表示は指定したモジュール名などがほぼそのまま表示されているだけですが、これを日本語に変更する方法は[[GuideI18n|国際化]]のところで説明します。 h2. プラグインメニューへの追加 プロジェクトでモジュールを有効にしてもまだ何も変わりません。実際にこのプラグインを使えるようにするためにはプロジェクトメニューに項目を追加する必要があります。 プロジェクトメニューにはこのプラグインで最初に表示させたいページに対応するアクションを追加します。サンプルでは foos コントロールの index アクションとなります。 メニュー項目の追加も init.rb で行います。先ほどの記述の後に以下を加えます。 <pre><code class="ruby"> menu :project_menu, :standard, { :controller => 'foos', :action => 'index' } </code></pre> メニューの項目の追加は *menu* メソッドを使います。 <pre><code class="ruby"> menu(menu, item, url, options={}) </code></pre> 第 1 引数はメニューの名前です。ここではプロジェクトメニューを指定します。指定できるメニューは [[GuideSampleSpec|サンプル仕様]] で説明した 4 つです。 |_. メニュー |_. メニュー名 | | トップメニュー | :top_menu | | アカウントメニュー | :account_menu | | プロジェクトメニュー | :project_menu | | アプリケーションメニュー | :application_menu | 第 2 引数はメニューの項目名です。 第 3 引数はメニューをクリックしたときのリンク先の URL を指定します。 第 4 引数はオプションでここでは省略しています。 h2. Rails での URL の指定方法 前節のメニューで行った URL の指定方法は *link_to* などでの他の Rails のリンクの指定方法と同じです。 URL の指定方法についてもう少し詳しく説明しましょう。 URL として文字列を指定すると単純にその文字列が url として使用されますが、ハッシュで指定するとそれを元に URL を生成します。 指定するキーはコントローラ名(:controller)、アクション名(:action)と ID名(:id) で、そのキーの値を使って次のようなアドレスとなります。 <pre> サーバアドレス/コントローラ名/アクション名/ID名 </pre> ID 名は省略可能で省略されると ID 名の部分はなくなります。ただし、ここで省略しているのはプロジェクトメニューから呼ばれると自動的に ID 名はプロジェクトの識別名になるためです。サンプルのアドレスは以下のようになります。(プロジェクトの識別名は demo にしています) <pre> http://127.0.0.1:3000/foos/index/demo </pre> このアドレスの指定によりコントロールのアクションが実行されることになります。この場合は FoosController の index メソッドが呼ばれます。 ID は *param* というハッシュクラスの変数に格納されてます。param は $ マークは付いてませんが、グローバル変数のようなものだと考えてください。 プロジェクトの識別名は :id を使わずに :project_id に入れて、config/routes.rb でアドレスの表示を変える方法もあります。サンプルでは :id を使った方が簡単だと思ったのでこちらの方法をとっています。 h2. index ページの表示 Redmine を再起動してモジュールを追加したプロジェクトを開いてみましょう。プロジェクトメニューに *Standard* が追加されています。 !sample_proj_menu.png! このメニューをクリックして下さい。 index.html.erb の内容のページが表示されます。 !index_no_project.png! コントローラの index メソッドの中にはまだ何も書いていません。それにもかかわらず、 index ページが表示されています。これはコントローラのアクションが実行されるとアクション名のメソッドが実行され、デフォルトの状態ではアクション名に対応する views のファイルが表示されるためです。 スケルトンとして生成されたファイルは index.html.erb ですが、検索されるファイルはアクション名の後は .rhtml, .erb のような Erb の html を表す拡張子であれば何でもかまいません。 h2. @project の設定 ただし、表示されたページよく見ると何か変なことに気づくと思います。これは他のプロジェクトメニューと違いプロジェクトが開かれていないためです。このページをプロジェクトに属するものするためには FoosController クラスのインスタンス変数 *@project* に値を設定する必要があります。 FoosController クラスの末尾に次のような @project を設定する *find_project* メソッドの定義を追加します。外から呼ばれることはありませんので、private メソッドにしています。 <pre><code class="ruby"> class FoosController < ApplicationController unloadable # : private def find_project @project = Project.find(params[:id]) rescue ActiveRecord::RecordNotFound render_404 end end </code></pre> params[:id] にはプロジェクトの識別名が入っています。 Project はプロジェクト用のモデルクラスです。 *find* メソッドは引数にプロジェクト識別名を渡すと、データベースから識別名が一致するプロジェクトを探し、Project のオブジェクトを返すクラスメソッドです。 Project クラスも ActiveRecord::Base クラスを継承して作成されており、データがみつからないと *ActiveRecord::RecordNotFound* の例外が発生します。コントローラ内で例外が発生すると通常の http サーバの場合 Internal Error のページになってしまいます。(WEBrick では詳細なエラー情報の画面になります。) この例外をキャッチして *render_404* を実行しています。 これはファイルが見つかりませんといった http の 404 エラーのページを表示するメソッドです。 定義した find_project メソッドを index メソッドの中で呼び出せばプロジェクト内のページとして表示されます。 h2. before_filter アクションは index だけではありません。他のアクションのメソッドでも同様に find_project を呼び出す必要があります。じゃ、 index の find_project をコピーして、他のメソッドにもペーストしていって ... と思った人はちょっと待ってください。 それでは同じことを何度も書く羽目になります。 Rails には DRY(Don't Repeat Yourself) という繰り返し禁止の方針がありました。何か繰り返しを避ける方法があるはずです。 実際、避ける方法は用意されています。それは *before_filter* です。これでメソッドを指定するとそのメソッドはアクションのメソッドの前に呼ばれるようになります。 こちらはコントローラクラスの先頭の方に追加します。 <pre><code class="ruby"> class FoosController < ApplicationController unloadable before_filter :find_project # : </code></pre> h2. authorize before_filter はカンマで区切って複数のメソッドを指定することが出来ます。もう一つ追加してみましょう。 <pre><code class="ruby"> class FoosController < ApplicationController unloadable before_filter :find_project, :authorize # : </code></pre> 追加した *authorize* はページを開いた時にログインしていない場合はログインのページ行く Redmine のメソッドです。通常、プロジェクトメニューから開かれるので、ログインしていることが多いと思いますが、ブラウザで前に開いていたページをもう一度開くといった設定がしてある場合などでは直接ページが指定されることもあります。そういったときにもちゃんとログインできるようにすべてのアクションの前に実行しておく必要があります。 権限の設定で index や show では設定によってはログインしてなくても、表示できる場合があるのではと疑問を持った方もいると思いますが、そういう場合も Redmine がログインしないように上手く処理してくれます。 権限の判定には現在のプロジェクトの情報が必要となります。before_filter は追加した順に実行されますので必ず find_project, authorize の順で記述して下さい。 ここまで設定して、もう一度 [Standard] のメニューを選択してみてください。今度はプロジェクトのページとして開かれているはずです。 !index_no_tab.png! まだ、少し変なところがあります。メニュー項目が選択状態になっていませんね。これを解決するにはコントローラ内で *menu_item* を使ってメニュー項目を指定します。 <pre><code class="ruby"> menu_item :メニュー項目のシンボル </code></pre> このメソッドで指定しなくてもメニュー項目が選択状態になることがあります。実はどうしたらそうなるのかは私もよく分かりません。とりあえず、選択状態にならないときはこのメソッドで指定してみてください。 これまでの記述を追加したコントローラのファイルの中身は次のようになります。 <pre><code class="ruby"> class FoosController < ApplicationController unloadable menu_item :standard before_filter :find_project, :authorize def index end def new end def show end def edit end private def find_project @project = Project.find(params[:id]) rescue ActiveRecord::RecordNotFound render_404 end end </code></pre> これでプロジェクトメニューにきちんと登録できるようになりました。 !index_tab.png! ---- | [[プラグイン開発ガイド|^]] | [[GuideControlSkelton|<<]] | [[GuideI18n|>>]] |