目前分類:ROR (11)

瀏覽方式: 標題列表 簡短摘要
今天發現一個只有在 Passenger 上才會遇到的問題。
原本在 config/environment.rb 裡的程式碼:



在本機端測試沒有問題,卻在 Server 端發現出現以下的錯誤

undefined method `chinese_permalink' for #

後來 trace error_log 發現是在 environment.rb 那裡出錯,
看了一下想是不是應該在 initialize 前就做
ActiveRecord::Base.send :include, ChinesePermalink

試了之後果然得到正確的結果。

我想這應該是 passenger 在處理 rails boot 的 require 順序有所不同造成的,
查了一下大概找到有文章在討論這個: 研究 Rails 3 的 boot process 和 initialization process
先記下來,再找個時間來讀

沒力小僧 發表在 痞客邦 留言(0) 人氣()

使用 Phusion Passenger + Apache 跑 Rails App 時,RAILS_ENV 的設定也一併要在 Apache 設定檔裡處理。

官方文件寫的是使用 RailsEnv,但在實際上使用後失效,還是跑在 default 的 production 上。

找了一下發現也有其他人有同樣狀況,參考這篇文章使用 SetEnv RAILS_ENV staging 後,終於可以正常運作了。

沒力小僧 發表在 痞客邦 留言(0) 人氣()

想要讓公司內的 rails 網站吃 ldap 認證,在安裝上遇到一些小麻煩。

在經過同事 stephon 的幫忙和自己整理後如下:

#sudo apt-get install libldap2-dev libsasl2-dev
都要裝 dev 版本

#sudo gem install ruby-ldap
安裝 ruby-ldap。但這樣還沒完

參考官方文件會發現還需要下面步驟

#cd /usr/local/lib/ruby/gems/1.8/gems/ruby-ldap-0.9.11
#sudo ruby extconf.rb --with-openldap2
#sudo make
#sudo make install

這些都完成後會在 /usr/local/lib/ruby/site_ruby/1.8  底下發現多了 ldap 資料夾,
此時就可以正常操作了

沒力小僧 發表在 痞客邦 留言(0) 人氣()

專案用到的 thinking_sphinx 沒有正常執行 crontab index,於是下去 trace,
發現是在 cap deploy 時造成的錯誤。

在 contab 裡的設定如下:


而我的 cap deploy 是這樣跑的
#cap deploy -n
* 以上略
* executing `deploy:after_update_code'
* executing `thinking_sphinx:start'
* executing `thinking_sphinx:configure'
* executing "cd /myapp/current; rake RAILS_ENV=production thinking_sphinx:configure"
* executing "cd /myapp/current; rake RAILS_ENV=production thinking_sphinx:start"
* executing `deploy:symlink'
* executing "rm -f /myapp/current && ln -s /myapp/releases/20100525083656 /myapp/current"

因為在執行 thinking_sphinx:configure thinking_sphinx:start 後才做 symlink,
結果生出來的 production.sphinx.conf 就這樣被砍掉,
而 crontab 執行時就會找不到 production.sphinx.conf 檔。

因為很明顯的是 thinking_sphinx 的 bug,於是看了一下版號,是個有夠舊(1.2.12, 現在[2010/05/25]是 1.3.16)
跑去找最新的版本來測試,果然。

* executing `deploy:after_update_code'
* executing `thinking_sphinx:start'
* executing `thinking_sphinx:configure'
* executing "if [ -d /myapp/releases/20100525085056 ]; then cd /myapp/releases/20100525085056; else cd /myapp/current; fi; rake RAILS_ENV=production thinking_sphinx:configure"
* executing "if [ -d /myapp/releases/20100525085056 ]; then cd /myapp/releases/20100525085056; else cd /myapp/current; fi; rake RAILS_ENV=production thinking_sphinx:start"
* executing `deploy:symlink'
* executing "rm -f /myapp/current && ln -s /myapp/releases/20100525085056 /myapp/current"

production.sphinx.conf 就不會因為 deploy:symlink 的關係消失了。

算是一個有趣的 trace bug 經驗,還趁機熟悉了一些事。

沒力小僧 發表在 痞客邦 留言(0) 人氣()

因為需要使用一個 Exception 可以指定 status 以處理各種不同的狀況,所以試著寫寫看。
Custom Exception: WebException

:lib/web_exception.rb

:app/controllers/application_controller.rb 新增

另外,如果要在 development 模式看到你修改的結果,要記得修改 config/environments/development.rb
將config.action_controller.consider_all_requests_local 設定為 true。
而如果是使用 locahost 本機端開發,還要記得在 app/controllers/application_controller.rb 加上一段 code
來強制 disbale local request

沒力小僧 發表在 痞客邦 留言(0) 人氣()

當網站採用 OpenID 登入時,在測試碼上遇到的問題:
因為 OpenID 認證部分是跟自己網站沒有關係的,在測試時無需“真實”使用 OpenID 來認證。
所以我們便假造之。

作法如下:

修改 features/support/env.rb



上述的程式碼意義是:當你要執行 open_id_authentication 這個 method 之前,就直接回傳假造的 Result 回去了。
只是測試而已,犯不著真的跑去 OpenID Provider 那邊去擾民。

除了狸貓換太子外,這段程式碼還有另一層意義:

在撰寫測試碼時要避免畫錯重點選錯目標
(像我在找到這解答前差點要寫測試碼來測試 open_id_authentication 這個 plugin 了),
我要測試的內容是“自身網站的登入機制“,
像 OpenID 的部分因為採用第三方 plugin,那便不該是我測試的項目
(plugin 本身自己就該有自身的測試碼)
認準目標是撰寫測試碼最重要之處。

相關連結:



沒力小僧 發表在 痞客邦 留言(0) 人氣()

save 可以接收一個參數 :perform_validation => true/false,預設為 true。
當 perform_validation 被設為 false 時不會過 validation.

save! 沒有任何額外參數,一定會過 validation.

在執行 save 時,如果有任一個 before_* validation 失敗,整個 save 會回傳 false。

而在執行 save! 時,before_* validation 失敗則是會丟一個例外 ActiveRecord::RecordNotSaved 回來。

所以在應用上:

  • 在 controller 裡一般使用 save,免得每一個 save 失敗都要做 rescue,因為使用者的輸入錯誤是很自然會發生的;
  • 而在像是 rake 或 test 中,就應該使用 save!,方便 debug.

 

參考:Rails API - Class:ActiveRecord::Base#save

沒力小僧 發表在 痞客邦 留言(0) 人氣()

這篇文章講的很清楚:attributes= (ActiveRecord::Base) - APIdock

這樣要繞過 attr_protected 的 column 時就不用一個一個手動指定了。

沒力小僧 發表在 痞客邦 留言(0) 人氣()

1. 使用 Model.increment_counter(counter_name, id):

003:0> User.increment_counter(:hit_counter, 1)
User Update (0.8ms)   UPDATE `users` SET `hit_counter` = COALESCE(`hit_counter`, 0) + 1 WHERE (`id` = 1)

2. 使用 Model.update_counters(id, attribute => ammount)

011:0> User.update_counters(1, :hit_counter => 50)
User Update (0.7ms)   UPDATE `users` SET `hit_counter` = COALESCE(`hit_counter`, 0) + 50 WHERE (`id` = 1)

第1個方法可以單純的做+1動作,第2個方法多了指定要加多少。

另外,Rails 還有一個 instance method: increment,但我其實不建議使用它。因為他不是用 sql 的加法來達成 incrment.

013:0> user = User.first
014:0> user.increment(:hit_counter, 2)
015:0> user.save
User Update (0.2ms)   UPDATE `users` SET `updated_at` = '2009-10-26 04:09:00', `hit_counter` = 163 WHERE `id` = 1

這種方式有可能出現 race condition.

沒力小僧 發表在 痞客邦 留言(0) 人氣()

這裡主要是講 database 使用 mysql 的狀況。

在 Rails 裡,對於 text 的指定只有一種。

而有時我們需要更大的欄位,比方說 medium text, big text。因為有時候,大一點還是比較好。

這時候在 migration 裡的作法有兩種個方式:

第一種是以指定 limit 大小的方式讓 mysql 自行將欄位設定為 medium text (請注意 "content" ):

  1. class CreateArticles < ActiveRecord::Migration
  2.   def self.up
  3.     create_table :articles do |t|
  4.       t.string    :title
  5.       t.text      :content, :limit => 64.kilobytes + 1
  6.       t.timestamps
  7.     end
  8.   end
  9.  
  10.   def self.down
  11.     drop_table :articles
  12.   end
  13. end
  14.  

第二種是在 self.up 後再 exeucte 自行生成你要的欄位:

  1. class CreateArticles < ActiveRecord::Migration
  2.   def self.up
  3.     create_table :articles do |t|
  4.       t.string    :title
  5.       t.timestamps
  6.     end
  7.     execute "ALTER TABLE articles ADD `content` MEDIUMTEXT NOT NULL AFTER `title`"
  8.   end
  9.  
  10.   def self.down
  11.     drop_table :articles
  12.   end
  13. end

沒力小僧 發表在 痞客邦 留言(0) 人氣()

在 Rails 裡對做 CRUD 時,有個方便的實作。

params 表示 form parameters,為 hash 型式 (column => value),這樣子若要把 form 的資料接過來只需要一行。

除了 new 之外,還支援這樣的方式:

方便歸方便,但也衍生了一個問題,那就是使用者的 form 表單裡塞了一些我們不希望被修改的 column 時,這些指令依然會被執行。

比方說帳號欄位,我們通常是不希望被修改的。

於是這時候可以使用 attr_accessible 或 attr_protected 來保護這些欄位

attr_protected :account

這樣在使用 new, attributes=(attributes), update_attributes(attributes) 時,account 欄位會被保護,不被這些 method 改變其值。

而如果我們真的要改變的話,需要自行指定。

以下是 Rails api 給的範例,可以更清楚我在講什麼

沒力小僧 發表在 痞客邦 留言(0) 人氣()