Rails App 一般是使用資料庫裡的每筆資料id作為網址連結,例如 http://example.com/product/1
,然而這樣的網址是沒有意義的,對資料庫來說就只是一個遞增的數字,對使用者而言也只是個不知為何的數字,所以我們用FriendlyId這隻gem來客製化我們的網址,他的運作原理是讓 ActiveRecord 產生 Slug ,並將他做為 Record的識別。 使用前 http://example.com/product/4323454
使用後 http://example.com/product/aeron-chair
如果每筆資料的slug是唯一的,就可以利用http://example.com/product/aeron-chair
來讀取到你的record。
Gem的設定
# rails4以上版本要裝5.0.0以上的friendly_id
gem 'friendly_id', '~> 5.0.0'
# babosa這個gem是讓我們做字元轉換的,支援中文網址
# 例如:http://example.com/product/阿龍椅
gem "babosa"
建立必要的資料表
rails generate friendly_id
rails generate migration add_slug_to_products slug:string:uniq
rake db:migrate
資料表建立完成後在Produc Model下進行設定
class Product < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
end
這裡的friendly_id設定name的意思是指說,將原本網址對應到的 :id
變成直接對應該product model裡面的 :name
欄位
接下來的作法是在有用到 Product.find(params[:id])
的地方將其修改為 Product.friendly.find(params[:id])
可是如果有一百個地方都用到呢?那豈不是要全改? 也許你可以這樣做
#將以下這行原先的註解拿掉
config.use :finders
這樣一來直接用原本的Product.find(params[:id])
就會自動指向你所設定的 :name
囉
到目前這個步驟應該成功將無意義的網址變成顯示product name的網址了
如果舊資料沒有slug怎麼辦呢?
舊有的資料如果沒有slug會一樣用原本的:id
去執行,總不能手動一個一個改! 所以我們先進rails console
輸入Product.find_each(&:save)
, 這裡的Product請替換成你要做slug的table!
解決中文產生出亂碼網址
如果你的name欄位是英文數字,在顯示上是沒問題的,但一遇到中文,他會因為該Gem所使用到 ActiveSupport 的 parameterize,把非 a-z,0-9,-
的字元全部變成 -
,於是中文字就會被吃掉了,然後輸出預設的UUID格式,像是2bc08962-b3dd-4f29-b2e6-244710c86106這樣的東西。
為了解決中文無法顯示的困擾,我們在前面有提到這隻Gembabosa
,他可以把 UTF-8 字元處理好,而不是都消滅,跟 FriendlyId 配合只要把 normalize_friendly_id override 就可以了
class Product < ActiveRecord::Base
extend FriendlyId
# 把原先的:name改成:slug_candidates
friendly_id :slug_candidates, use: :slugged
# 原本是input.to_s.parameterize,但是parameterize只支援英文跟數字,所以改用babosa的to_slug
def normalize_friendly_id(input)
input.to_s.to_slug.normalize.to_s
end
# 定義slug_candidates,預設會找第一個,如果有重複的name就會找第二個(name-price),最後才會生成亂序
def slug_candidates
[
:name,
[:name, :price]
]
end
end