(3) Url項目はそのURLへリンクさせる

一覧表示ページでリンクを張る

ビュー list.rhtml
app/views/softwares/list.rhtml

一覧表示の描画はlist.rhtmlの中で完結している。その中の該当箇所を見つけて...

<h1>Listing softwares</h1>

<table>
  <tr>
  <% for column in Software.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
  </tr>
  
<% for software in @softwares %>
  <tr>
  <% for column in Software.content_columns %>
    <td><%=h software.send(column.name) %></td>......[1]
  <% end %>
    <td><%= link_to 'Show', :action => 'show', :id => software %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => software %></td>
...(以下省略)...

これは既に利用しているlink_toで実現できると思い、[1]の部分をifを使ってこんなコードで置き換えた。

<% if column.name == 'url' %>
  <td><%= link_to software.send(column.name), software.send(column.name)  %></td>
<% else %>
  <td><%= software.send(column.name) %></td>
<% end %>

ところが、link_to_ifを使えば、この1メソッドで済んでしまうことに気づいた!1メッソドで済むというのは良いことだ!分かりやすい。

 <td><%= link_to_if column.name == 'url', 
                      software.send(column.name), 
                      software.send(column.name)  %></td>

個別表示ページでリンクを張る

ビュー show.rhtml
app/views/softwares/show.rhtml

個別表示もUrl項目を表示している箇所を見つけて...

<% for column in Software.content_columns %>
<p>
  <b><%= column.human_name %>:</b> <%=h @software.send(column.name) %>......[2]
</p>
<% end %>

<%= link_to 'Edit', :action => 'edit', :id => @software %> |
<%= link_to 'Back', :action => 'list' %>

同じく、変更してみた。

<%= link_to_if column.name == 'url',
               @software.send(column.name), 
               @software.send(column.name)  %>

hの問題

べつにスケベなことが問題なのではない。(分かっていると思いますが...)
満足しかけたが、一つ些細なことに気が付いた。

<%=h software.send(column.name) %>
<%=h @software.send(column.name) %>

上記は修正前のコードだが、どちらも<%=h %>で囲まれている...。
それなら修正後も<%=h %>で囲んでしまえばいいじゃないかとやってみると、これが良くない。

hを付けると、このようにHTMLのソースとして表示されてしまい、リンク機能が発揮されないのだ。
それなら「hのことは忘れよう、たった1文字なのだから」と思いかけたが、なぜ、わざわざ二つの書き方があるのか調べてみた。

HTMLタグを利用して新規登録してみる
Title
<h1>TEST</h1>
Description
<table border="5" cellspacing="15" cellpadding="10">
<tr>
<td>こんな</td><td>表現も</td><td>可能</td>
</tr>
</table>

新規登録ページで、タイトルと説明の欄にHTMLタグを含めて書いてみると、こんな表現も出来てしまう。

セキュリティ対策

表現の幅が広がっていいじゃないかと思うのだが、実は良いことばかりではないらしい...。
もしも、良くないことを考える人がいて、そこに悪意のあるJavaScriptなんかが書かれてしまうと...。どんな事が起きるか想像もつかないが、何かの悪事に利用されるのはご免だ。
ネットワークに繋がっている環境では、誰もが接続できる環境にあるので、一握りの悪意かもしれないが、注意しておく必要があるらしい。webアプリケーション開発の習慣として身に付けたいので、hを付けるべきところにはちゃんと付ける事にした。
調べてみれば簡単なことで、h(対象文字列)のように、対象文字列を囲ってあげれば良いだけだ。最終的には以下のようにした。これでHTMLタグを付けて入力しても、表示されるだけで機能しないはず。

list.rhtml
<td><%= link_to_if column.name == 'url', 
                     h(software.send(column.name)), 
                     software.send(column.name)  %></td>
show.rhtml
<%= link_to_if column.name == 'url',
               h(@software.send(column.name)), 
               @software.send(column.name)  %>
      • 厳密にはurlの入力内容も検証する必要があるかも...。きっと、便利なvalidateを使って上手いやり方があるんだろうなー。
link_to_ifメッソドの構文
link_to_if リンクタグを付ける条件, 表示文字列, URL文字列
  • リンクタグを付ける条件が満たされていれば、表示文字列はURLへリンクする。
  • さもなければ、表示文字列だけ表示する。