XDite曾經在「以 ROR 打造網站,設計盲點所引發的惡搞危機」這篇文章中提到Rails的scaffold所建立出來的程式(或說開發者很習慣直接以id操作Model),由於在URL上是直接以流水號的方式呈現,我們便可以利用一些簡單的程式爬完某個網站的特定頁面,來取得所有的文章、所有的使用者頁面。

事實上XDite應該是有在另外一場活動提過因應的對策,雖然我沒抓下來聽,不過我猜應該是改變Controller的設計方式,以亂碼或是其他方式來產生URL。

首先在Table裡面加上「permalink」這個column,如果你是要在既有的table上新增,可以使用migration來新增欄位(當然你也可以砍掉重練XD)

class AddPermalink < ActiveRecord::Migration
  def self.up
    add_column :posts, :permalink, :string
    add_index :posts, :permalink, :unique => true
  end

  def self.down
    remove_index :posts, :permalink
    remove_column :posts, :permalink
  end
end

接下來在Model裡面定義permalink的產生方式

class Post < ActiveRecord::Base
  before_create :generate_permalink

  protected
    def generate_permalink
      # 定義permalink的產生方式
      self.permalink = Time.now.strftime("%Y-%m-%d_") + rand(100000).to_s
    end
end

這邊我是用時間加亂數的方式產生permalink,事實上這樣的寫法還是有可能重複,不如用SHA或MD5的方式來產生Permalink也不錯(雖然長了點)。

class Post < ActiveRecord::Base
  before_create :generate_permalink

  protected
    def generate_permalink
      # 用標題+時間進行md5的編碼
      require 'digest/md5'
      self.permalink = Digest::MD5.hexdigest(self.title + Time.now.to_s)
    end
end

往後在連結可以使用:

 link_to post.title, 
                :controller => "post", 
                :action => "show", 
                :id => post.permalink

在Controller裡面Action的寫法則是:

class PostController < ApplicationController
  def show
    @post = Post.find_by_permalink(params[:id])
  end
end