at posts/single.html

本文中のリンク (BracketName)

簡易だけど検索機能を付けたので、次に BracketName を作る。 BracketName とは、 [[ と ]] で括った文字列のこと。 Wiki だと別ページへのリンクになるんだけど RandomNote だとその言葉を検索するリンクになるのが面白い。 以下、 RandomNote の説明文より引用。

[[ ]] で囲まれた言葉は、その言葉を検索するリンクになります。

さて、 HikiDoc を使いながらどうやって文法を拡張するかだけど、同じく HikiDoc を使っている tDiary のソース (wiki_style.rb) を参考にさせてもらった。 WikiSection#to_html のソースを抜粋。

 html = HikiDoc::new( string, :level => 3, :empty_element_suffix => '>'  ).to_html.strip
 html.gsub!( %r!<span class="plugin">\{\{(.+?)\}\}</span>!m ) do
   "<%=#{CGI.unescapeHTML($1)}%>"
 end
 html.gsub!( %r!<div class="plugin">\{\{(.+?)\}\}</div>!m ) do
   "<p><%=#{CGI.unescapeHTML($1)}%></p>"
 end

なるほど。 HikiDoc で HTML に変換した後に、正規表現で置換 (gsub!) しているのか。 同じように、ヘルパーの parse メソッドを修正する。

   def parse(body)
-    HikiDoc.new(body, :level => 3).to_html
+    html = HikiDoc.new(body, :level => 3).to_html
+    html.gsub!(%r|<a href="(.+?)">(.+?)</a>|m) do
+      href, text = $1, $2
+      href == text ? link_to_search(text) : Regexp.last_match
+    end
+    html
   end
+
+  def link_to_search(text)
+    link_to(text, { :action => 'search', 'search[word]' => text },
+                  { :post => true })
+  end

検索へのリンクを生成するロジックは、これまた RandomNote の特徴であるサイドバーの検索履歴で今後も使いそう。 なので、link_to_search という別メソッドにしておいた。 といっても、内部では link_to を呼んでいるだけなんだけど。

link_to は便利なメソッド。 アクション (:action) とパラメータ ('search[word]') を指定するだけで、必要な URL を生成してくれる。 この場合、コントローラは同じ NoteContoroller なので、 URL は

http://192.168.92.210:3000/note/search?search%5Bword%5D=test

のようになる。

これで BracketName は完成。 リポジトリに登録しておしまい。 もうリビジョン14か。

追記

…また忘れてた。 検索への呼び出しは GET じゃなくて POST を使うようにしている。 何故かというと、 RandomNote での検索は副作用(検索数のカウント)を伴うから。 クローラによって消したはずのキーワードがいつの間にか復活するという問題が出ているみたいだし。 一般的に、副作用を伴う操作は POST を使った方がいい。

ということで、コントローラ (NoteController) の search アクションを、 POST のみ受け付けるようにした。

verify :method => :post, :only => [ :create, :update, :search ],
       :redirect_to => { :action => :list }

これでリビジョン15

関連する日記