プロジェクト

全般

プロフィール

Tips wiki » 履歴 » リビジョン 3

リビジョン 2 (Mitsuyoshi Yoshida, 2011/07/07 02:57) → リビジョン 3/4 (Mitsuyoshi Yoshida, 2011/07/07 03:00)

h1. wiki 編集機能の追加 

 {{>toc}} 

 プラグインに wiki 編集機能を付ける方法の Tips です。 
 [[プラグイン開発ガイド]] では簡単な wiki 編集機能は付けました。ここでは他の wiki のように以下の機能も追加します。 

 * プレビュー 
 * 添付ファイル 

 wiki 編集機能だけの場合の説明はプラグイン開発ガイドを見てください。 

 * [[GuideNewAction#フォーム内のパラメータ|フォーム]] 
 * [[GuideActionElse#詳細表示-show-アクション-|表示]] 

 h2. サンプルコード 

 * "表示":http://code.google.com/p/myoshida-rp/source/browse/#svn%2Ftrunk%2FTips%2Falias%2Fwiki 
 * "ダウンロード":http://code.google.com/p/myoshida-rp/downloads/detail?name=sample-wiki.zip 

 サンプルはプラグイン開発ガイドのコードを改造したものです。 

 *フォーム* 

 !wiki_form.png! 

 *表示* 

 !wiki_show.png! 



 h2. プレビュー 

 プレビューでは新しくページを開くことなく、ページの内容を変更する必要があります。こういう処理には JavaScript が必要になります。しかし、 Rails ではこれを簡単に行える *link_to_remote* という関数が用意されてます。 Rails では *_remote* と付くのは JavaScript 実行用のもので、 link_to_remote では JavaScript を実行するリンクが作成できます。 

 :update オプションを使った link_to_remote では、リンクをクリックするとアクションを実行し、その結果をページの指定した場所に挿入します。 

 h3. 表示 

 プレビュー用のリンクを新規作成(new.html.erb)と編集(edit.html.erb)のフォーム送信ボタンの横に付けます。 wiki 編集機能を改良した new.html.erb は次のようになります。 edit.html.erb もほぼ同じように修正します。  

 <pre><code class="rhtml"> 
 <h2><%=l(:label_foos_new)%></h2> 

 <% labelled_tabular_form_for :foo, @foo, 
                              {:html => {:multipart => true, :id => 'foo-form'}} do |f| %> 
     <%= render :partial => 'foos/form', :locals => {:form => f} %> 
     <%= f.submit l(:button_create) %> 
     <%= link_to_remote l(:label_preview),  
                        { :url => {:action => 'preview', :id => @project }, 
                          :method => 'post', 
                          :update => 'preview', 
                          :with => "Form.serialize('foo-form')", 
                          :complete => "Element.scrollTo('preview')" 
                        }, :accesskey => accesskey(:preview) %> 
 <% end %> 
 <div id="preview" class="wiki"></div> 
 </code></pre> 

 変更点は 3 つです。 

 * フォームタグに ID を要素を付ける。 
 ** {:html => {:multipart => true, :id => 'foo-form'}} 
 * link_to_remote でプレビュー用のリンクを付ける 
 * プレビューの表示場所を付ける 
 ** <notextile><div id="preview" class="wiki"></div></notextile> 

 multipart も追加していますが、これは次で説明する添付ファイル用のものです。 

 link_to_remote は引数は以下のものを渡します。 

 # 表示名 
 # オプション 
 # html オプション 

 表示名には Redmine で定義されたプレビューのラベルを使い、 html オプションとしてプレビュー用のアクセスキーを設定しています。アクセスキーを付けるとどう変わるのかはよく分かりませんが、 Redmine のチケット、ニュース等は付いているの一応付けています。 

 link_to_remote の主な指定はオプションで行います。 

 |_. オプション |_. 説明 | 
 | :url        | アクションを指定するための url です。 preview アクションは今回新たに追加します。 | 
 | :method     | get または post を指定します。文字数が 256 を超える可能性があるので post を指定しています。 | 
 | :update     | 結果の挿入先の html 要素の ID を指定します。 | 
 | :with       | リンクと一緒に実行する JavaScript を記述します。リンクを実行したときにフォームの内容を params 変数に格納するための処理を行っています。 フォームに ID を追加したのはここで使用するためです。 | 
 | :complete | アクション実行後の JavaScript の処理を指定します。処理が完了したら、スクロールしてプレビューの内容が表示されるようにしています。 | 


 h3. コントローラ 

 コントローラ( foos_controller.rb )に link_to_remote から呼ばれる preview を追加します。 

 <pre><code class="ruby"> 
   def preview 
     @text = params[:foo][:description] 
     render :partial => 'common/preview' 
   end 
 </code></pre> 

 2 行目でフォームの説明(description)フィールドの内容を *@text* に入れ、3 行目で挿入する部分描画を行っています。 *code/preview* は Redmine で用意されているビュー用のテンプレートファイルで以下のような内容です。 

 <pre><code class="rhtml"> 
 <fieldset class="preview"><legend><%= l(:label_preview) %></legend> 
 <%= textilizable @text, :attachments => @attachements, :object => @previewed %> 
 </fieldset> 
 </code></pre> 

 (@attachements のつづりが間違っている気がしますが、 1.2.0 ではこうなってました) 


 h3. preview アクションの権限 

 アクションを追加した場合には忘れずに init.rb で権限を指定していないとエラーになってしまいます。 

 <pre><code class="ruby"> 
   project_module :standard do 
     permission :view_foos, :foos => [:index, :show, :preview] 
     permission :manage_foos, {:foos => [:new, :edit, :destroy]}, 
                :require => :member 
   end 
 </code></pre> 



 h2. 添付ファイル 

 添付ファイルを使えるようにするにはいろいろやることがあります。 

 * モデル 
 ** 添付ファイルを使えるように指定 
 ** プロジェクトメソッドの追加 
 * ビュー 
 ** フォーム 
 *** マルチパートにする 
 *** 添付ファイル用のフィールドを追加 
 ** 表示 
 *** wiki 解析で添付ファイルを使うように指定 
 *** 添付ファイルの表示 
 * コントロール 
 ** attachments ヘルパーのインクルード 
 ** 添付ファイルの保存 

 h3. モデル 

 <pre><code class="ruby"> 
 class Foo < ActiveRecord::Base 
   unloadable 

   belongs_to :project 

   acts_as_attachable :delete_permission => :manage_foos 

   # : 

   def project 
     Project.find(:first, :conditions => "projects.id = #{project_id}") 
   end 
  
 end 
 </code></pre> 

 *acts_as_attachable* メソッドを書くことにより、 foo クラスで添付ファイルが使えるようになります。 acts_as_attachable は Redmine が使用している Rails のプラグインで他のプラグインと同様に vendor/plugins 以下にデフォルトで置かれているものです。 
 引数はオプションで、ここでは添付ファイルを削除するのにサンプルデータの管理権限が必要なようにしています。 

 添付ファイルを使用する場合、 プロジェクトのオブジェクトを返すプロジェクトメソッドが必要となります。なぜ、必要なのかは実は私もよく分かりません。分かりませんが作っておかないと正常に動作しないのでとりあえず付けておきましょう。 

 *belongs_to* はモデルクラスの関係を記述しています。ここでの記述で foo は project に属していることになります。 
 project メソッドは自分の *project_id* メンバを使って、 [[GuideForProject#project-の設定|コントローラの時と同じ]] ようにプロジェクトオブジェクトを取得しています。 


 h3. ビュー 

 h4. フォーム 

 まず、 プレビューで書いたコードのようにしてフォームはマルチパート(multipart)にしておく必要があります。これは プレビューのところで書いたようにフォームはマルチパート(multipart)にしておく必要があります。これは http の決まりのようなものです。 

 また、新規作成と編集で共通して使うフォーム( _form.html.erb ) に以下の行を追加します。ここも Redmine で使われているものをそのまま部分描画として使用します。 

 <pre><code class="rhtml"> 
 <p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p> 
 </code></pre> 


 h4. 表示 

 wiki 解析結果の表示も少し変更する必要があります。 

 <pre><code class="rhtml"> 
 <% unless @foo.description.blank? %> 
   <p><strong><%=l(:field_description)%></strong></p> 
   <div class="wiki"> 
     <%= textilizable @foo.description, :attachments => @foo.attachments %> 
   </div> 
 <% end %> 

 <% if @foo.attachments.any? %> 
     <hr /> 
     <%= link_to_attachments @foo %> 
 <% end %> 
 </code></pre> 

 wiki 解析時に添付ファイルも考慮するように *textilizable* のオプションで添付ファイルを渡しています。 
 また、 *link_to_attachments* で添付ファイルの情報とリンクを説明の下に追加しています。 


 h3. コントロール 

 添付ファイルを扱うメソッドは Attachments ヘルパーで定義されています。これを使うためにモジュールを include する必要があります。 

 <pre><code class="ruby"> 
   helper :attachments 
 </code></pre> 

 データの保存が終わった後、添付ファイルも保存する必要があります。 @foo.save が成功した後に以下の行を new, edit それぞれのメソッドで追加します。 

 <pre><code class="ruby"> 
         Attachment.attach_files(@foo, params[:attachments]) 
         render_attachment_warning_if_needed(@foo) 
 </code></pre> 

 1 行目が添付ファイルを保存する処理で、 2 行目がそのエラー処理を行っています。 

 ---