傑克達與瑞兒絲的大小事

快速筆記整理網站開發上碰到的各種技巧和問題,免得年紀大忘光,至少還有一個地方可以查找

Monthly Archives: 五月 2012

擴展 Paperclip 加入 hash 目錄參數,自訂 :path 和 :url

Paperclip 是 Rails 的一個上傳圖片插件,它可以很方便的幫助我們實現上傳圖片和裁剪圖片的功能。在安裝完 Paperclip 後,Paperclip 會有一組預設指定圖片顯示和存放的路徑,如下:

:url => "/uploadfiles/:class/:attachment/:id/:basename/:style.:extension",
:path => ":rails_root/public/uploadfiles/:class/:attachment/:id/:basename/:style.:extension"

但是因應專案的需求不同,你可能會要重新調整這組存放和顯示的路徑設定,例如,針對上傳的圖片會依照使用者放到對應的目錄下,所以我們需要在路徑加上使用者 ID,如下:

:url => "/uploadfiles/:user_id/:class/:attachment/:id/:basename/:style.:extension",
:path => ":rails_root/public/uploadfiles/:user_id/:class/:attachment/:id/:basename/:style.:extension"

這時該怎麼做呢?

實作方式:

1. 建立 config/initializers/paperclip_extensions.rb,加入以下程式碼

Paperclip.interpolates :user_id do |attachment, style|
return current_user.id
end

2. 修改 model 中 Paperclip 定義的 :path 和 :url 路徑

:url => "/uploadfiles/:user_id/:class/:attachment/:id/:basename/:style.:extension",
:path => ":rails_root/public/uploadfiles/:user_id/:class/:attachment/:id/:basename/:style.:extension"

參考文章:

https://github.com/thoughtbot/paperclip

http://stackoverflow.com/questions/4041373/paperclip-custom-path-and-url

http://www.oschina.net/question/54100_24721

ActiveRecord 新增操作的 create 和 create! 二者差別

雖然這是基本觀念,不過有時還是會分不清這二者的差別和使用時機,還是筆記一下吧!

以下的資料來源均摘錄於 ihower – Ruby on Rails 實戰聖經 ActiveRecord 該篇的內容說明

二者差異:

create 和 create! 就等於 new 完就 save 和 save!,有無驚嘆號的差別在於 validate 資料驗證不正確的動作
無驚嘆號版本會回傳布林值(true或false)
有驚嘆號版本則是驗證錯誤會丟出例外

使用時機:

何時使用驚嘆號版本呢?
save 和 create 通常用在會處理回傳布林值(true/false)的情況下 (例如在 controller 裡面根據成功失敗決定 render 或 redirect),否則預期應該會儲存成功的情況下,請用 save! 或 create! 來處理,這樣一旦碰到儲存失敗的情形,才好追蹤 bug。

參考文章:

http://ihower.tw/rails3/activerecord.html

設定 Capistrano deploy 保留的 release 數量

Capistrano 預設保留的數量是 5 個,但如果你想保留更少的話,可以這樣做

實作方式:

1. 開啟 capistrano 的 deploy.rb 設定檔,加上

set :keep_releases, 1

其中 1 表示你要保留的 release 數量

2. 設定在執行完 deploy 操作後,馬上清理 release,可在文件最後加上

after "deploy:update", "deploy:cleanup"

3. 另外你也可以透過 command line 下達指令來控制要保留的 release 數量,如下

bundle exec cap deploy:cleanup -s keep_releases=1

參考文章:

http://stackoverflow.com/questions/2121957/capistrano-clean-up-old-releases

http://geoff.evason.name/2009/03/27/setting-a-capistrano-variable-from-the-command-line/

解決 Rails 3.1.1 整合 ckeditor gem 的 assets precompile 問題

由於專案開發使用到文字編輯器,選用了 ckeditor gem,而專案的 Rails 剛好是 3.1.1 的版本,就在順利將 ckeditor 整合至專案並 deploy 至 production 後才發現線上環境竟然找不到 ckeditor 的 config 設定檔,查了老半天,才發現原來是 assets precompile 的問題,這時有了方向也就比較容易找解答,也順便筆記

問題發生狀況:

Rails 版本: 3.1.1
ckeditor gem 版本:  3.7.1
paperclip gem 版本: 3.0.2

無法顯示 ckeditor 編輯器畫面,出現以下錯誤訊息

Failed to load resource: the server responded with a status of 404 (Not found)

解決方法:

1. 開啟 config/environments/production.rb

2. 加入

config.assets.precompile += %w( ckeditor/* )

3. 再次 deploy 執行 assets:precompile 即可

參考文章:

https://github.com/galetahub/ckeditor

http://stackoverflow.com/questions/7914924/integrating-ckeditor-with-rails-3-1-asset-pipline

Rails 專案遇到錯誤時,如何執行發信通知功能 (進階)

接續剛剛提到的專案遇到錯誤執行發信通知功能,如果有一些額外的資訊需要表達在信件中時,該怎麼做呢?

貼心的 exception_notification_rails3 另外有提供了一個 data 的 section 可以讓使用者自訂訊息內容

使用方法:

1. 開啟剛剛在 config/environments/production.rb 的設定,加上粗體表示的那行文字

config.middleware.use ::ExceptionNotifier,
:email_prefix => "[ERROR] ",
:sender_address => %{"Notifier" <notifier@yourdomain.com> },
:exception_recipients => %w{exceptions@yourdomain.com},
:sections => %w(data request session environment backtrace)

2. 接下來要自訂訊息內容,開啟 app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
before_filter :authenticate
before_filter :set_exception_data
...
def set_exception_data
# used for exception notification
user = User.current
return true if user.nil?
user_info = "名字: #{user.display_name}, 電子郵件: #{user.mail}, 部門: #{user.department}"
env['exception_notifier.exception_data'] = { :data=>{ :user => user_info , :deploy => Rails.env } }

true
end

3. 設定完成,之後便會在錯誤信件中看到定義的內容,結果如下:

-------------------------------
Data:
-------------------------------
* user: 名字: 小王, 電子郵件: smallwang@yourdomain.com, 部門: 資訊部
* deploy: production

參考文章:

http://qa.taobao.com/?p=13030

Rails 專案遇到錯誤時,如何執行發信通知功能

最近在專案上遇到一個需求,也就是當 Rails 專案在線上環境遇到錯誤時,要能發信通知開發者,方便快速反應修正問題。透過咕歌大神搜尋後,找到幾個解決方案,其中利用 exception_notification_rails3 gem 看來是最佳的解法,趕快筆記一下

使用方法:

1. 修改 Gemfile,加入以下指令

$ gem 'exception_notification_rails3', '~> 1.2.0', :require => 'exception_notifier'

2. 設定完成後,請執行 bundle 安裝 gem

$ bundle

3. 因為只針對線上 production 的環境才需要執行發信操作,所以開啟 config/environments/production.rb 加入以下設定

config.middleware.use ::ExceptionNotifier,
:email_prefix => "[ERROR] ",
:sender_address => %{"Notifier" <notifier@yourdomain.com> },
:exception_recipients => %w{exceptions@yourdomain.com}

email_prefix: 信件主旨的前綴詞,可自行定義
sender_address: 信件的寄件者
exception_recipients: 信件的收件者,如果有多個收件者,記得用空白隔開,如: %w{abc@yourdomain.com xyz@yourdomain.com}

附註:

如果你希望在 development 和 production 二個環境下都要能收到錯誤通知,可以直接在 config/applicaiton.rb 加入設定

參考文章:

https://github.com/rails/exception_notification

http://ryanwilliams.org/2010/Nov/04/exception-notification-in-rails-3

 

Instance 變數的快取

學 Ruby 也有一段時間了,但一直忘記「 ||= 」這個指令的使用方式,還是快速筆記一下加強記憶吧

使用意義:

根據 Rails Casts 的影片說明,一般我們在 Ruby 執行

@user = User.find(1)

當下達這樣的指令時,Ruby 就會在背後執行一段 SQL 語法取得我們指定的資料,而收到一個 request 時可能需要執行很多次的這樣的操作,相對地也就會對 database 執行同樣多次的 SQL 查詢,是還滿秏效能的,這時,我們就可以使用 OR 符號,將剛剛的指令修正如下

@user ||= User.find(1)

第一次執行時,由於 @user 是 nil,所以 Ruby 便會生成 SQL 語法向 database 取得資料,一旦當 @user 有了資料,不再是 nil 值時,下次再執行這段指令,Ruby 就不會再生成 SQL 語向 database 取資料,而是直接返回 @user 變數值,如此一來就可以大大減少效能的損秏

簡單來記,就是當變數為空值時才執行指令的操作,否則返回變數保存的內容

參考文章:

http://railscasts.com/episodes/1-caching-with-instance-variables?view=asciicast

如何避免 Nokogiri 生成 html 時加上 doc 標籤

最近開發碰到一個需求很特殊,在使用 Nokogiri 解析 html 內容時,最後輸出 html 時,本文內容裡不要有 DTD 標籤描述,剛上網查到一種解法,照慣例先筆記

實作方式:

原本透過 Nokogiri 在產出 html 時,只需使用 to_html 方法,但 Nokogiri 會自動將 DTD 標籤補上,如下:

require 'nokogiri'

doc = Nokogiri::HTML('<p>foobar</p>')
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body><p>foobar</p></body></html>

如果不想在產出 html 時加上 DTD 標籤,可以利用以下的方式:

doc = Nokogiri::HTML.fragment('<p>foobar</p>')
puts doc.to_html
# >> <p>foobar</p>

改為使用 HTML.fragment 知會 Nokogiri 只使用片段內容來解析,那麼 to_html 產出的內容就不會包含 DTD 標籤了

參考文章:

http://stackoverflow.com/questions/4723344/how-to-prevent-nokogiri-from-adding-doc-tags

http://nokogiri.org/