分類目錄歸檔:Ruby on Rails

期待或關注中的Ruby on Rails相關圖書

我把我關注的Ruby on Rails的圖書列在這裡,做個提醒。
The Rails Way (Addison-Wesley Professional Ruby Series)
Pro ActiveRecord: Databases with Ruby and Rails (Pro)
Advanced Rails Recipes: 72 New Ways to Build Stunning Rails Apps
Agile Testing with Ruby and Rails
Professional Ruby Collection: Mongrel, Rails Plugins, Rails Routing, Refactoring to REST, and Rubyisms
Scaling Rails: Building Giant Websites
Foundations of RSpec: Behavior-Driven Development with Ruby and Rails
Advanced Rails

發表在 Ruby on Rails | 留下評論

Open MDB file on Ubuntu, convert it to CSV, import it to Rails

Open MDB file on Ubuntu, convert it to CSV, import it to Rails
MDB is a data file format used by Microsoft Office Access. To open and view MDB files on ubuntu, you can install a tools named mdbtools :

sudo apt-get install libmdbtools mdbtools mdbtools-gmdb

This will also install MDB viewer, and you can use it to open and view MDB files. It also can be used to export tables to CSV(Comma-separated_values) files.

And here is an example importing CSV data into Rails model:
require ‘csv’
CSV::Reader.parse(File.open(‘/path/to/file’, ‘rb’)).each do |row|
    Production.create(:name => row[1],
        :price => row[3])
end

發表在 Ruby on Rails, 信息處理 | 留下評論

在ubuntu6.06上安裝apache2.2X + mysql + PHP + Ruby on Rails + Mongrel Cluster

到現在已經安裝了好幾次服務器了。總結出了一些經驗,在這裡和大家分享一下。

說明
我使用的linux是ubuntu 6.06 server cd版本。選第一項安裝最基本的系統文件,不自動安裝LAMP服務,因為ubuntu 6.06自帶的apache2是2.0X的,不適合做mongrel cluster的前台,安裝自帶的apache2.0X之後卸載它比較麻煩,所以乾脆不要自動安裝LAMP服務,而手動安裝apache2.2。

ubuntu 6.06 server cd的基本安裝只安裝系統必要文件,不安裝其它服務,甚至連ssh都要手動:
sudo apt-get install ssh
安裝,請大家注意要安裝上ssh才能遠程訪問。

安裝準備

加本地ubuntu源,加快下載速度
sudo nano /etc/apt/sources.list
加入速度比較快的源,如cn99的:
deb http://ubuntu.cn99.com/ubuntu/ dapper main restricted universe multiverse
deb http://ubuntu.cn99.com/ubuntu/ dapper-updates main restricted universe multiverse
deb http://ubuntu.cn99.com/ubuntu/ dapper-security main restricted universe multiverse
deb http://ubuntu.cn99.com/ubuntu/ dapper-backports main restricted universe multiverse
deb http://ubuntu.cn99.com/ubuntu-cn/ dapper main restricted universe multiverse

更新系統
sudo apt-get update
sudo apt-get dist-upgrade

準備必要文件
sudo apt-get install build-essential

創建下載源碼文件夾

cd ~
mkdir src
cd src

安裝zlib
wget http://www.zlib.net/zlib-1.2.3.tar.gz
tar xvfz zlib-1.2.3.tar.gz
cd zlib-1.2.3/
./configure –prefix=/usr/local
make
sudo make install
cd ..

安裝Apache2.2
下載安裝apche2.2
sudo dpkg –purge apache apache2
wget http://apache.rmplc.co.uk/httpd/httpd-2.2.4.tar.gz
tar xvfz httpd-2.2.4.tar.gz
cd httpd-2.2.4/
./configure –prefix=/usr/local/apache2 –enable-mods-shared=all –enable-deflate –enable-proxy –enable-proxy-balancer –enable-proxy-http
make
sudo make install
cd ..

測試apache2.2
啟動apache2.2
sudo /usr/local/apache2/bin/apachectl start
訪問測試
http://xxx.xxx.xxx.xxx(服務器IP)
停止apache2.2
sudo /usr/local/apache2/bin/apachectl stop

讓apache2.2在系統啟動時自動運行
sudo cp /usr/local/apache2/bin/apachectl /etc/init.d/apachectl
sudo chmod +x /etc/init.d/apachectl
sudo nano /etc/init.d/apachectl
修改文件,增加:
#!/bin/sh
#
# chkconfig: – 85 15
# description: Apache is a web server.
sudo /usr/sbin/update-rc.d apachectl defaults

增加apache用戶,增強系統安全性
sudo adduser –system apache
sudo nano /usr/local/apache2/conf/httpd.conf
修改文件,將
User daemon
Group daemon
改成:
User apache
Group nogroup

PHP模塊安裝
如果你不想在服務器中使用php網站,直接跳過本節
下載安裝php4(因為我的服務器只是用來運行早點的php程序,php4夠用了)
sudo apt-get install flex
wget http://au2.php.net/get/php-4.4.7.tar.gz/from/cn.php.net/mirror
tar xvfz php-4.4.7.tar.gz
cd php-4.4.7
./configure –with-apxs2=/usr/local/apache2/bin/apxs –with-mysql –disable-cgi –with-zlib –with-gettext
make
sudo make install
sudo cp php.ini-dist /usr/local/lib/php.ini
cd ..

設置php
sudo nano /usr/local/apache2/conf/httpd.conf
修改文件,
增加(如果已經加上就不用了)
LoadModule php4_module        modules/libphp4.so

AddType application/x-gzip .gz .tgz
之後增加:
AddType application/x-httpd-php .php
修改
DirectoryIndex index.html

DirectoryIndex index.html index.php default.php

測試php
在網站目錄(默認/usr/local/apache2/hdocs/)創建test.php文件,內容
<?php
phpinfo();
?>
然後訪問:
http://xxx.xxx.xxx.xxx/test.php
應顯示系統php模塊信息。

安裝MySQL
sudo apt-get install mysql-server mysql-client

修改root用戶密碼
sudo mysqladmin -u root password 新密碼
sudo mysqladmin -u root -h localhost password 新密碼

如果要進行其它基本設置,修改/etc/mysql/my.cnf文件。

mysql數據備份與恢復
備份
mysqldump -u 用戶名 -p 數據庫名 > 備份文件名
恢復
mysql -u 用戶名 -p 數據庫名 < 備份文件名

安裝ruby1.8.6
ubuntu 6.06自帶的ruby是1.8.4, 因為在使用1.8.4版的ruby時我遇到mongrel提示ruby版本過舊的問題,所以自行編譯安裝1.8.6版的ruby.

安裝ruby1.8.6
wget http://rubyforge.org/frs/download.php/18421/ruby-1.8.6.tar.gz
sudo tar -xvf ruby-1.8.6.tar.gz
cd ruby-1.8.6
./configure
make test
make
sudo make install

安裝ruby1.8.6後在運行script/console時遇到了
      /usr/local/lib/ruby/1.8/irb/completion.rb:10:in `require’:
      no such file to load — readline (LoadError)
錯誤,解決辦法是
安裝readline

sudo apt-get install libncurses5-dev libreadline5-dev
cd ext/readline
ruby extconf.rb
make
sudo make install
cd ../../..

ruby gems安裝
sudo wget http://rubyforge.org/frs/download.php/11289/rubygems-0.9.0.tgz
tar -xvzf rubygems-0.9.0.tgz
cd rubygems-0.9.0
sudo ruby setup.rb
sudo gem update –system
cd ..

安裝libmysql
sudo apt-get install libmysql-ruby libmysql-ruby1.8 libruby1.8
安裝好這個後
irb
irb(main):001:0> require ‘mysql’
還是提示出錯,於是我安裝mysql gem
sudo gem install mysql
但安裝出錯。。。。
奇怪的是後來發現RoR網站可以正常運行,沒有問題。網友如果解決了這個問題,請留言一下。

安裝Rails
sudo gem install rails –include-dependencies
注意linux平台安裝過程要選帶ruby的rails。

安裝Mongrel Cluster
sudo gem install daemons gem_plugin mongrel mongrel_cluster –include-dependencies
同上,linux平台安裝過程要選帶ruby的程序。

增加一個mongrel用戶,增強系統安全性
sudo adduser mongrel
將網站文件歸到這個用戶
sudo chown -R mongrel:mongrel /www/app
上面/www/app為RoR程序目錄

創建mongrel群

sudo mongrel_rails cluster::configure -e production -p 8000 -N 3 -c /www/app -a 127.0.0.1 –user mongrel –group mongrel
其中/www/app為RoR程序目錄
8000為mongrel群開始端口
-N 3中的3為mongrel群中的mongrel服務器數量,3表示3個mongrel組成這個群,群使用的端口從8000開始,8000,8001,8002三個。
上面的命令將會在RoR程序/www/app/config目錄下生成mongrel_cluster.yml文件。
將新文件歸到mongrel用戶
sudo chown -R mongrel:mongrel /www/app/config/mongrel_cluster.yml

啟動mongrel群測試
在當前RoR程序根目錄(如上面的/www/app)下運行
sudo mongrel_rails cluster::start

讓mongrel cluster在系統啟動時自動運行
sudo mkdir /etc/mongrel_cluster
sudo ln -s /www/app/config/mongrel_cluster.yml /etc/mongrel_cluster/app.yml
sudo cp /usr/local/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.2/resources/mongrel_cluster /etc/init.d/
上面的/usr/local/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.2/是mongrel gem所在的目錄。
修改mongrel_cluster文件
sudo nano /etc/init.d/mongrel_cluster
在CONF_DIR之上加入一行:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin
解決一些情況下因為mongrel找不到程序而不能在系統啟動時自動運行的問題。
sudo chmod +x /etc/init.d/mongrel_cluster
sudo /usr/sbin/update-rc.d -f mongrel_cluster defaults
手動修改mongrel cluster的啟動順序,讓它在最後運行,解決有可能發生的另一些啟動問題。
sudo mv /etc/rc2.d/S20mongrel_cluster /etc/rc2.d/S99mongrel_cluster

讓Apache成為mongrel的前台
修改httpd.conf文件(默認在/usr/local/apache2/conf/目錄下)
最後加入:
NameVirtualHost 192.168.1.1
<Proxy balancer://cslog_cluster>
  BalancerMember http://127.0.0.1:8000
  BalancerMember http://127.0.0.1:8001
  BalancerMember http://127.0.0.1:8002
</Proxy>

<VirtualHost 192.168.1.1>
    ServerName www.cslog.cn
    DocumentRoot /www/cslog/public
  RewriteEngine On
  RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /maintenance.html [L]
  # Rewrite index to check for static index.html
  RewriteRule ^/$ /index.html [QSA]
  # Rewrite to check for Rails cached pages with .html extentions
  RewriteRule ^([^.]+)$ $1.html [QSA]
  # All dynamic requests get sent to the cluster
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ balancer://cslog_cluster%{REQUEST_URI} [P,QSA,L]
  # Deflate for clients that support it.
  AddOutputFilterByType DEFLATE text/html text/plain text/xml
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Error and access logs.
  ErrorLog logs/cslog_error_log
  CustomLog logs/cslog_access_log combined
</VirtualHost>
文件中的cslog_cluster可以自己命名,但要對應。
8000,8001,8002為mongrel群對應的端口。

總結
到這裡,ubuntu6.06上的apache2.2, mysql, PHP, Ruby on Rails , Mongrel Cluster安裝設置已經完成。下午一次全過程大概用了兩個小時,如果寫成腳本,應該可以系統自動安裝,可以更快完成全過程。

發表在 Ruby on Rails, 站長文檔 | 3 條評論

Ruby on Rails的session和session存儲方案

session:頁面間的信息保存手段。

使用:
賦值
session[:person] = @user
讀取
Hello #{session[:person]}
清除
session[:person] = nil
全部清除
reset_session

Ruby on Rails提供的session存儲方案:
PStore (文件存儲,默認方式)
ActiveRecordStore(數據庫)
DRbStore
FileStore
MemoryStore

各存儲方案在性能上的比較:
Ruby on Rails Session Container Performance

如何使用ActiveRecordStore(數據庫)做為session存儲方案
使用數據庫作為session儲存方案可以讓網站更方便地擴展成多服務器網站。使用方法:
1. 運行 rake db:sessions:create
2. 將config/environment.rb, uncomment 中下行的注釋#去除:
       config.action_controller.session_store = :active_record_store
3. 運行rake db:migrate
4. 重啟服務器。

linux上用來清除長時不用的session的cron命令:
$RAILS_APP_DIR/script/runner ‘ActiveRecord::Base.connection.delete("DELETE FROM sessions WHERE updated_at < now() – INTERVAL 1 HOUR")

發表在 Ruby on Rails | 標籤為 | 3 條評論

RailsSpace: Building a Social Networking Website with Ruby on Rails 學習筆記

RailsSpace: Building a Social Networking Website with Ruby on Rails>是一本從Ruby on Rails基礎教起的實例教程。但與共為實例教程的<Agile Web Development with Rails> 相比,<RailsSpace: Building a Social Networking Website with Ruby on Rails>有着自己明顯的特色。後者教授的不僅是Ruby on Rails的語言知識, 而且夾雜了更多的編程技巧和思想,我感覺更適合具有一定Ruby on Rails基礎的人員,使之從“知道Ruby on Rails知識”提升到“在實戰中運用Ruby on Rails"的新層次。

雖然我看過<Agile Web Development with Rails>, 但還是我在<RailsSpace: Building a Social Networking Website with Ruby on Rails>中發現的新奇的東西:

<%= link_to_unless_current "Home",     :action => "index" %>
原來Rails中還有link_to_unless_current。

MySQL的發音是"My-Ess-Cue-Ell".

YAML 是 Ain’t a Markup Language 的縮寫。

rake db:migrate VERSION=0, 可以用來月光寶盒數據庫版本。

save比save()有更重的ruby味。

在irb的console中可以使用reload!來重載被修改後的環境(我原來一直是退出來再進一次!)

正則實例:    /^[A-Z0-9._%-]+@([A-Z0-9-]+\.)+[A-Z]{2,4}$/i,
這個用來校驗email地址。
^:字串行的開始
[A-Z0-9._%-]+:至少一位下列有效字符:大寫字母,數字,點,下劃線或桿線
@
([A-Z0-9-]+\.)+:至少一組以點分隔的帶有大寫字母,數字或桿線的字串
[A-Z]{2,4}:2至4位的大寫字母
$:字串行結束
i:因為電郵地址不區分大小寫字母,這個i指定正則不對字母的大小寫不感冒。

用戶的密碼不一定要加密後存到數據庫中去。

為了使fieldset/legend HTML標籤在IE中正常顯示,可能要進行CSS Hack.
/* Hack to get IE to display fieldset/legend correctly */
html fieldset {
  position: relative;
}
html legend {
  position:absolute;
  top: -1em;
  left: .5em;
}
html fieldset {
  position: relative;
  margin-top:1em;
  padding-top:2em;
  padding-bottom: 2em;
}

可以在layout中加入顯示debug信息的功能。

分離出SCREEN_NAME_SIZE = 20,PASSWORD_SIZE = 10,EMAIL_SIZE = 30等HTML表格參數,方便統一管理。在view中以下面的方法調用:
<div class="form_row">
<label for="email">Email:</label>
<%= form.text_field :email,
:size => User::EMAIL_SIZE,
:maxlength => User::EMAIL_MAX_LENGTH %>
</div>

inspect可以用來顯示post的內容:aise params[:user].inspect

在Ruby中只有false和nil才是false的。

可以為系統的錯誤指示息做一套漂亮的CSS外衣。如:
/* Error Reporting Styles */
.fieldWithErrors {
  margin: 2px;
   padding: 2px;
   background-color: red;
   display: table;
}
#errorExplanation {
  border: 2px solid red;
  padding: 7px;
  padding-bottom: 12px;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}
#errorExplanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12pt;
  margin: -7px;
  background-color: #c00;
  color: #fff;
}
#errorExplanation p {
  color: #333;
  margin-bottom: 0;
  padding: 5px;
}
#errorExplanation ul li {
  font-size: 11pt;
  list-style: square;
}
…………..

rake doc:app可以用來生成實例文檔。

title = assigns(:title) 產生 title = @title的效果.

測試的命令:rake test:functionals,rake test:units, rake, rake stats,ruby test/functional/user_controller_test.rb -n /test_login_failure/, rake recent….

關於錯誤信息,0的使用還有sprintf:
>> @error_messages = ActiveRecord::Errors.default_error_messages; 0
=> 0
>> @error_messages[:too_short]
=> "is too short (maximum is %d characters)"
>> sprintf(@error_messages[:too_short], 17)
=> "is too short (maximum is 17 characters)"

使用數據庫作為session儲存方案可以讓網站更方便地擴展成多服務器網站。使用方法:
1. 運行 rake db:sessions:create
2. 將config/environment.rb, uncomment 中下行的注釋#去除:
       config.action_controller.session_store = :active_record_store
3. 運行rake db:migrate
4. 重啟服務器。

當發生與session相關的錯誤時,可以試着清空數據庫的session表。

用下列語句來快速校驗用戶密碼。
user = User.find_by_screen_name_and_password(screen_name, password)

session[:user_id]返回的是數值,而not session[:user_id].nil?返回的是boolean值,有時候使用兩者程序效果一樣,但對編程者本身的頭腦邏輯清晰度卻會有區別。

使用mixin,將一個通用method放到helper中去,這樣不但view中,而且在controller中加入include ApplicationHelper語句後也可以使用這個method.甚至test…

大量使用外套(abstraction layer)!!

user.save和user.save!都可以用來發送將user存儲到數據庫這一指令。區別在存儲失敗之後的表現上。user.save失敗後只會返回一個false值(可以用if user.save判斷), 而一旦user.save!失敗,將會產生一個exception錯誤。所以在使用意圖上,允許一定條件下(控制之中的)失敗時,用user.save,而期望它一定要成功(不然就要啟動應急rescue措施)時,用user.save!.

在一class內可以省略語句中attribute和function里的self關鍵字(self.id->id),但有一例外,就是在賦值的時候, self.name = "Jom"不能省為name = "Jom",因為後者只會產生一個值為"Jom"的本地變量!

這個實例可以用來解決找不到定義好的變量的問題:<% field_title = nil if not defined?(field_title) -%>

用名詞命名controller,用動詞命名action.

當發現所有instance變量為nil時,檢查一下是不是誤用到了RoR的保留字。

將類DB_STRING_MAX_LENGTH = 255的常量放到config/environment.rb文件中,這樣可以在全局中引用。

@user.spec["first_name"]和@user.spec.send("first_name")等同於@user.spec.first_name

在rout.rb中加入
map.profile ‘profile/:screen_name’, :controller => ‘profile’, :action => ‘show’
後可以使用  profile_url(:screen_name => ‘foobar’)生成profile的url.
在view之外的地方引用可以先 helper :profile (它和include ProfileHelper的不同點???)
included ProfileHelper 是為了使用 profile_for. partial中引用的話要用helper: profile????

MySQL的TEXT欄不支持默認值。手動設置方法
  def initialize
    super
    QUESTIONS.each do |question|
      self[question] = ""
    end
  end

initial function在class新建instance時會被運行。如果class有上級,會自動繼承上次的initialize function. 在子class中加initialize function, 使用super,這樣會調用上級initialize function.

生成所有單字母串的方法:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
或 %w(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

使用列表樣式的實例:
<% @letters.each do |letter| %>
<% letter_class = (letter == @initial) ? "letter_current" : "letter" %>
<%= link_to letter, { :action => "index", :id => letter },
:class => letter_class %>
<% end %>

如果action之後還要用到id, rout.rb中沒有用到id的url要加入:id=>nil的參數。

pluralize的用法
>> pluralize(0, "box")
=> "0 boxes" #0時用複數
>> pluralize(1, "box")
=> "1 box"
>> pluralize(2, "box")
=> "2 boxes"
>> pluralize(2, "box", "boxen")
=> "2 boxen" #自定義複數形式的方法

原來安裝和使用ferret搜索引擎的方法這樣簡單:
1安裝ferret gem
> sudo gem install ferret
2下載安裝acts_as_ferret插件
> ruby script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret
Feeret首次搜索一個model時會耗費一定的時間在Rails的根目錄下的index目錄生成索引文件。當Ferret出問題時,可以試着在停止網頁服務器後刪除這個索引目錄,讓它重新生成索引文件。

合併兩個實例列用concat+uniq!
@users.concat(hits.collect { |hit| hit.user }).uniq!

為實例列排序
@users = @users.sort_by { |user| user.spec.last_name }

search form 使用GET request

可用   Spec.find(:all, :conditions => ["gender = :gender", params])來取代Spec.find(:all, :conditions => ["gender = ?", params[:gender]])

改寫默認string class的方法在lib/string.rb中
class String
#寫自己的method
end

replace能用另一個object取代自己,如:
  def capitalize_each
    space = " "
    split(space).each{ |word| word.capitalize! }.join(space)
  end
  # Capitalize each word in place.
  def capitalize_each!
    replace capitalize_each
  end

寫一個檢查整數的method:
class Object
  # Return true if the object can be converted to a valid integer.
  def valid_int?
    begin
      Integer(self)
      true
      rescue ArgumentError
      false
    end
  end
end
注意nil.valid_int? 返回 true (Integer(nil) == 0) 但 nil.valid_float? 返回 false(Float(nil) 產生 ArgumentError exception).

使用.errors.add("xxx")的方法寫校檢method.
  def valid_input?
    @spec = Spec.new
    if @spec.valid? and not zip_code.blank? and location.nil?
      @spec.errors.add(:zip_code, "does not exist in our database")
    end
    unless miles.nil? or miles.valid_float?
      @spec.errors.add("Location radius")
    end
    # The input is valid iff the errors object is empty.
    @spec.errors.empty?
  end
在view中定製引用錯誤提示信息:
<%= error_messages_for(‘spec’).sub(‘prohibited this spec from being saved’,
‘occurred’) %>

沒有super class的module helper中不帶任何class.所以要自己require:
module ApplicationHelper
  require ‘string’

使用File.join生成文件目錄,以適應不同平台的操作系統?

為了上傳圖片,必須使用multipart encoding。
<form action="upload" enctype="multipart/form-data" method="post">
<input id="avatar_image" name="avatar[image]" size="30" type="file" />
</form>

PNG (發音:"ping"), 指Portable Network Graphics格式.

使用system("ls")可以調用系統的ls命令。

上傳的文件如果小於15K,將是StringIO (string input-output)類,如果大於15K,將是Tempfile (temporary file)。 為了統一兩者,可以用File.open(source, "wb") { |f| f.write(@image.read) }將文件寫出,"wb" 這裡指 "write binary"。

errors.add(:image, "totally doesn’t work")將錯誤信息加到一個attribute之上。 errors.add_to_base("There’s no freaking way that worked")會將錯誤信息加到全局。

默認情況下電郵將以text格式發出; 參考:
http://wiki.rubyonrails.org/rails/pages/HowToSendHtmlEmailsWithActionMailer

重寫ActiveRecord的子class的initialize function後,可以在保留它的validation function的同時避免將數據寫到數據庫里。

Active Record的create=new+save, save返回boolean, create直接返回object.

在class內引用此class的class method可以省略class名。

destroy比delete更強大,更適合用來消除Active Record objects.

user.friends
user.requested_friends
user.pending_friends
可以這樣連串!!!
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = ‘accepted’"
has_many :requested_friends,
:through => :friendships,
:source => :friend,
:conditions => "status = ‘requested’"

RESTful式的URLs沒有action部分,因為它的格式是:/controller/id;modifier

has_many可以加上order參數:
has_many :posts, :order => "created_at DESC"

內置的time_ago_in_words method,畢竟有!!雖然我不喜歡這個。
Posted <%= time_ago_in_words post.created_at %> ago

format.html用來回應HTML文件請求,format.js可以用來回應Javascript請求。

使用js更新頁面
        render :update do |page|
            format.js
        end
action.rjs
          page.hide "add_comment_link_for_post_#{@post.id}"
          page.replace_html "new_comment_form_for_post_#{@post.id}",
          :partial => "new"
使用RJS文件,將controller中view的部分分開來,更合理。

Ajax的運行有可能使客戶機,特別是老機子變得很慢甚至癱瘓。

http://wiki.script.aculo.us/scriptaculous/show/CombinationEffectsDemo
中的很多特效中我最喜歡的是
 blind down/up, highlight,puff

如果Ajax運行不正常,可以先檢查log文件。

鏈接的href選項可以為不支持JavaScript的用戶提供常規鏈接。

rake db:migrate RAILS_ENV=production,準備production數據庫

- Linux/Apache/mod_proxy_balance/Mongrel 發布方案
- Caching和shared nothing scaling方案
- Subversion 版本管理
- Capistrano 發布版本控制

為網站寫一個管理後台??

在console中按production環境啟動
> ruby script/console production
> ruby script/console production –sandbox 不修改數據庫

查看日誌的最後一頁:
tail -f log/production.log

在本地訪問時Rails會公布全文錯誤信息,但遠程用戶會指向public/404.html 或 public/500.html 文件。

更多關注的書:
Practical Rails Social Networking Sites (Expert’s Voice)
The Rails Way (Addison-Wesley Professional Ruby Series)
Pro ActiveRecord: Databases with Ruby and Rails (Pro)
Advanced Rails Recipes: 72 New Ways to Build Stunning Rails Apps
Agile Testing with Ruby and Rails

發表在 Ruby on Rails | 留下評論

Extreme Programming and Test-Driven Development

Extreme Programming
Extreme Programming (or XP) is a software engineering methodology, the most prominent of several agile software development methodologies.

Extreme Programming Explained describes Extreme Programming as being:
    * An attempt to reconcile humanity and productivity
    * A mechanism for social change
    * A path to improvement
    * A style of development
    * A software development discipline


Test-Driven Development
The goal of TDD is to write clean code that works.

What is Test-Driven Development?
Test-Driven Development (TDD) is a software development technique that involves repeatedly first writing a test case and then implementing only the code necessary to pass the test. Test-driven development is a method of designing software, not merely a method of testing.

In addition to normal “did it pass?” testing, you can go the opposite route. By testing your application where the weak points are, you can fix it before it ever becomes an issue.

Test-Driven Development Cycle
1. Add a test
In order to write a test, the developer must understand the specification and the requirements of the feature clearly.
2. Run all tests and see the new one fail
testing the tests
3. Write some code
It is important that the code written is only designed to pass the test; no further (and therefore untested) functionality should be predicted and ‘allowed for’ at any stage.

KISS
Keep It Simple, Stupid.
Everything should be made as simple as possible, but no simpler.
                    –Albert Einstein

You Ain’t Gonna Need It
‘You Ain’t Gonna Need It’(YAGNI), is a reminder for programmers that one should never add functionality until it is necessary.

4. Run the automated tests and see them succeed
5. Refactor code

Refactoring
A code refactoring is any change to a computer program which improves its readability or simplifies its structure without changing its results.
List of refactorings

    * Encapsulate Field(e.g. providing methods that can be used to read/write to/from the field rather than accessing the field directly.)
    * Extract Method (to turn part of a larger method into a new method. By breaking down code in smaller pieces, it is more easily understandable. This is also applicable to functions)
    * Generalize Type (to making more general or more abstract some subset of the traits of a specific type. An example of generalizing a type would be moving a method from a child to a parent class for common use by all the parent class’ children, not just the original child.)
    * Pull Up (moving a method from a Subclass into a Superclass. )
    * Push Down (moving a method from a SuperClass into a SubClass.)
    * Rename Method (changing the name of a method into a new one that better reveals its purpose).

The cycle is then repeated, starting with another new test to push forward the functionality.

"Test-Driven Development Mantra" is known as red/green/refactor where red means fail and green is pass.

Benefits
By focusing on the test cases first, one must imagine how the functionality will be used by clients (in this case, the test cases). Therefore, the programmer is only concerned with the interface and not the implementation.
It allows a programmer to focus on the task at hand as the first goal is to make the test pass.
Ensuring that all written code is covered by a test.

Limitations
A test-driven development is only as good as its tests.

Reference
http://en.wikipedia.org/wiki/Test-driven_development
http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It
http://en.wikipedia.org/wiki/Refactoring

Related Resources
Test::Unit – Ruby Unit Testing Framework
A Guide to Testing the Rails
Test Driven Design for Ruby and Rails
Ruby, Rails, Test::Rails Cheat Sheet

發表在 Ruby on Rails | 標籤為 , , | 留下評論

REST and ActiveResource

REST (Representational State Transfer)
REST is An Architectural Style
It uses the following standards:

    *  HTTP
    * URL
    * XML/HTML/GIF/JPEG/etc (Resource Representations)
    * text/xml, text/html, image/gif, image/jpeg, etc (MIME Types)
The Whole WWW is a REST system!

RESTful

RESTafarians

HTTP methods: PUT, GET, POST and DELETE.
database operations: CREATE, READ, UPDATE, DELETE (CRUD)

URI -> Resource
REST Is a Conversation
The verbs of the REST conversation are the aforementioned request methods, while the nouns are URIs, A URI should be only a pointer to a resource.
e.g.
GET "/books/1"
DELETE "/books/1"

URI,URL and URN
A Uniform Resource Identifier (URI), is a compact string of characters used to identify or name a resource.

A Uniform Resource Locator (URL) is a URI that, in addition to identifying a resource, provides means of acting upon or obtaining a representation of the resource by describing its primary access mechanism or network "location".

Uniform Resource Name (URN) is a URI that identifies a resource by name in a particular namespace. (e.g. urn:isbn:0-395-36341-1)

Web service, a software system designed to support interoperable Machine to Machine interaction over a network.

Remote Procedure Call (RPC)

REST Is Design
A clear approach to controller-design that’ll reduce complexity for the implementer and result in an application that behaves as a much better citizen on the general web.

REST gives us a framework for simple but extensible application design.

ActiveResource
RailsConf Keynote: David Heinemeier Hansson Video the World of Resources
online video: http://www.scribemedia.org/2006/07/09/dhh/
download address: http://downloads.scribemedia.net/rails2006/01_dh_hansson.m4v
(the slides http://www.loudthinking.com/lt-files/worldofresources.pdf)

David Heinemeier Hansson’s blog on ActiveResources
http://www.loudthinking.com/arc/000593.html

script/generate scaffold_resource

http://www.xfront.com/REST-Web-Services.html
http://en.wikipedia.org/wiki/Representational_State_Transfer
http://en.wikipedia.org/wiki/Uniform_Resource_Identifier
http://en.wikipedia.org/wiki/Web_service
Rails Cookbook

發表在 Ruby on Rails, 信息處理 | 留下評論

Web Services on Rails note

By Kevin Marshall

The Basics
APIs(application programming interface)

three architectures:
Representational State Transfer (REST)
Simple Object Access Protocol (SOAP)
Extensible Markup Language Remote Procedural(XML-RPC)
(SOAP grew out of XML-RPC)

SOAP
Web service signatures are really just data types that the service either expects or returns.
WSDL(Web Service Description Language)
a WSDL file is an XML document that defines the interface to a SOAP service.

REST
URL, http
The world wide web itself can be considered a REST system.

Searching Yahoo using REST
need:
1.Connect( net lib)
2.store
3.Parse results ( REXML lib)

Yahoo! web service API (up to 5,000 requests/IP per day)

Google AJAX Search API

use the CGI library to escape our search term, ensuring that the search term is safe for use in our HTTP GET request:
query = CGI.escape("SEARCH TEXT")

https://www.google.com/accounts/NewAccount?continue=http://api.google.com/createkey&followup=http://api.google.com/createkey:

Searching Google Using SOAP or SOAP with WSDL Files
UTF-8 can contain special characters that Ruby can’t handle in a string, causing our driver to throw an XSD::ValueSpaceError error upon invocation. To avoid this problem, we manually set our encoding to UTF-8 using the XSD library.
XSD::Charset.encoding = ‘UTF8′

Displaying Photos from Flickr Using XML-RPC

Building Web Service Servers
Make sure you turn off layouts for the methods you’ll be using in your service
Associate RXML templates with the methods in your controllers, instead of RHTML templates
xml is an XML document object that’s available in any RXML template
xml.name("Kevin", :id => 1, "age" => "31")
# creates <name id="1" age="31">Kevin</name>

 xml.exampledata do
     xml.name("Kevin")
 end
 # creates <exampledata><name>Kevin</name></exampledata>

SOAP and XML-RPC Web Service Servers
ActionWebService (AWS)
 script/generate web_service YOURSERVICE YOURMETHOD1 YOURMETHOD2

 three dispatching options, :direct, :delegated, or :layered.
web_service_dispatching_mode:direct
:delegated or :layered is the best way to go for any large or complex web service
With :delegated, clients use a distinct URL for each method in the API
With :layered, clients use the same URL for all attached methods and rely on AWS to route the request based on information passed in its header

:expects and :returns symbols
Ruby types (:string, :int, :bool, :float, :time, :datetime, :date, and :base64), or the names of ActiveRecord::Base or ActionWebService::Struct classes (for example, Greeting or Account), or a single element array to represent arrays of objects (for example, [:string] to represent an array of Strings or [Account] to represent an array of ActionWebService::Struct Account objects).

 raise "Access denied!"

發表在 Ruby on Rails | 留下評論

Learning Ruby 1 Ruby.new

with <Programming Ruby 2nd>
Ruby Basic

                   Variables        &nb[-aa--]sp;          Constants and
Local          Global        Instance Class    Class Names
name           $debug        @name    @@total  PI

fish_and_chips $CUSTOMER     @point_1 @@symtab FeetPerMile
x_axis         $_            @X       @@N      String
thx1138        $plan9        @_       @@x_pos  MyClass
_26            $Global       @plan9   @@SINGLE JazzSong

statement modi?ers
puts "Danger, Will Robinson" if radiation > 3000
square = square*square while square < 1000

Regular Expressions
In Ruby, you typically create a regular expression by writing a pattern
between slash characters (/pattern/).

/P(erl|ython)/
This pipe character means “either the thing on the right or the thing on the left,” in this case either Perl or Python.
 /ab+c/ matches a string containing an a followed by one or more b’s, followed by a c.
/ab*c/ creates a regular expression that matches one a, zero or more b’s, and one c.

\s, which matches a whitespace character (space, tab, newline, and so on);
\d, which matches any digit;
\w, which matches any character that may appear in a typical word.
A dot ( . ) matches (almost) any character.

if line =~ /Perl|Python/

line.sub(/Perl/, ‘Ruby’)    # replace first ‘Perl’ with ‘Ruby’
line.gsub(/Python/, ‘Ruby’) # replace every ‘Python’ with ‘Ruby’

Blocks and Iterators
{ puts "Hello" }      # this is a block
do                    ###
  club.enroll(person)   # and so is this
  person.socialize      #
end                   ###

    def call_block
      puts "Start of method"
      yield
      yield
      puts "End of method"
    end
    call_block { puts "In the block" }
produces:
    Start of method
    In the block
    In the block
    End of method

def call_block
  yield("hello", 99)
end
call_block {|str, num| … }

iterators: methods that return successive elements from some kind of collection, such as an array.
   animals = %w( ant bee cat dog elk )  # create an array
   animals.each {|animal| puts animal } # iterate over the contents
# within class Array…
def each
  for each element    # <– not valid Ruby
    yield(element)
  end
end

Reading and ’Riting
puts writes its arguments, adding a newline after each.
print also writes its arguments, but with no newline.
printf, which prints its arguments under the control of a format stringejfkldfjai

發表在 Ruby on Rails | 留下評論

learning ruby 7, Expressions

[ 3, 1, 7, 0 ].sort.reverse   [7, 3, 1, 0]

Operator Expressions
a*b + c
(a.*(b)).+(c)

Miscellaneous Expressions
Command Expansion
`date`                   "Thu Aug 26 22:36:31 CDT 2004
"
`ls`.split[34]           "book.out"
%x{echo "Hello there"}   "Hello there
"
for i in 0..3
  status = `dbmanager status id=#{i}`
  # …
end

Assignment
a=b=1+2+3
a   →6
b   →6
a = (b = 1 + 2) + 3
a   →6
b   →3

attribute
de?ne a writable object attribute
class Song
  def duration=(new_duration)
    @duration = new_duration
  end
end
attribute assignment
song.duration = 234

Parallel Assignment
swap the values in two variables
a, b = b, a

x=0                               0
a, b, c = x, (x += 1), (x += 1)   [0, 1, 2]

a = [1, 2, 3, 4]
b, c =  a          b == 1,  c == 2
b, *c = a          b == 1,  c == [2, 3, 4]
b, c =  99, a      b == 99, c == [1, 2, 3, 4]
b, *c = 99, a      b == 99, c == [[1, 2, 3, 4]]
b, c =  99, *a     b == 99, c == 1
b, *c = 99, *a     b == 99, c == [1, 2, 3, 4]

Nested Assignments
b, (c, d), e = 1,2,3,4       b == 1, c == 2, d == nil,    e == 3
b, (c, d), e = [1,2,3,4]     b == 1, c == 2, d == nil,    e == 3
b, (c, d), e = 1,[2,3],4     b == 1, c == 2, d == 3,      e == 4
b, (c, d), e = 1,[2,3,4],5   b == 1, c == 2, d == 3,      e == 5
b, (c,*d), e = 1,[2,3,4],5   b == 1, c == 2, d == [3, 4], e == 5

Other Forms of Assignment

Conditional Execution
                                                                       The number zero is not interpreted as a false value. Neither is a zero-length string.

De?ned?, And, Or, and Not
and and or have the same precedence,
&& has a higher precedence than ||.

defined? 1          "expression"
defined? dummy      nil
defined? printf     "method"
defined? String     "constant"
defined? $_         "global-variable"
defined? Math::PI   "constant"
defined? a=1        "assignment"
defined? 42.abs     "method"

Operator     Meaning
==     Test for equal value.
===       Used to compare the each of the items with the target in the when clause of a case statement.
<=>   General comparison operator. Returns −1, 0, or +1, depending on   whether its receiver is less than, equal to, or greater than its argument.
<, <=, >=, >    Comparison operators for less than, less than or equal, greater than or  equal, and greater than.
=~       Regular expression pattern match.
eql?     True if the receiver and argument have both the same type and equal values. 1 == 1.0 returns true, but 1.eql?(1.0) is false.
equal?   True if the receiver and argument have the same object ID.
== and =~ have negated forms, != and !~.

The value of Logical Expressions
nil   and true    nil
false and true    false
99    and false   false
99    and nil     nil
99    and "cat"   "cat"

false or nil     nil
nil   or false   false
99    or false   99

words[key] ||= []
words[key] << word
=====>
(words[key] ||= []) << word

If and Unless Expressions
then
if song.artist == "Gillespie" then handle = "Dizzy"
elsif song.artist == "Parker" then handle = "Bird"
else handle = "unknown"
end

:
if song.artist == "Gillespie": handle = "Dizzy"
elsif song.artist == "Parker": handle = "Bird"
else handle = "unknown"
end

if song.artist == "Gillespie"
  handle = "Dizzy"
elsif song.artist == "Parker"
  handle = "Bird"
else
  handle = "unknown"
end

unless song.duration > 180
  cost = 0.25
else
  cost = 0.35
end
==>
cost = song.duration > 180 ? 0.35 : 0.25

If and Unless Modi?ers
mon, day, year = $1, $2, $3 if date =~ /(\d\d)-(\d\d)-(\d\d)/
puts "a = #{a}" if debug
print total unless total.zero?

Case Expressions
leap years must be divisible by 400, or divisible by 4 and not by 100.
     leap = case
            when year % 400 == 0: true
            when year % 100 == 0: false
            else year % 4       == 0
            end

case input_line
when "debug"
  dump_debug_info
  dump_symbols
when /p\s+(\w+)/
  dump_variable($1)
when "quit", "exit"
  exit
else
  print "Illegal command: #{input_line}"
end

case shape
when Square, Rectangle
  # …
when Circle
  # …
when Triangle
  # …
else
  # …
end

Loops
while line = gets
  # …
end

until play_list.duration > 60
  play_list.add(song_list.pop)
end

a=1
a *= 2 while a < 100
a -= 10 until a < 100
a   → 98

    file = File.open("ordinal")
    while line = file.gets
      puts(line) if line =~ /third/ .. line =~ /fifth/
    end
produces:
    third
    fourth
    fifth

Iterators
    3.times do
      print "Ho! "
    end
produces:
    Ho! Ho! Ho!

    0.upto(9) do |x|
      print x, " "
    end
produces:
    0123456789

    0.step(12, 3) {|x| print x, " " }
produces:
    0 3 6 9 12

    [ 1, 1, 2, 3, 5 ].each {|val| print val, " " }
produces:
    11235

For . . . In
for song in songlist
  song.play
end

    for i in ['fee', 'fi', 'fo', 'fum']
      print i, " "
    end
    for i in 1..3
      print i, " "
    end
    for i in File.open("ordinal").find_all {|line| line =~ /d$/}
      print i.chomp, " "
    end
produces:
    fee fi fo fum 1 2 3 second third

Break, Redo, and Next
while line = gets
  next if line =~ /^\s*#/   # skip comments
  break if line =~ /^END/   # stop at end
                    # substitute stuff in backticks and try again
  redo if line.gsub!(/`(.*?)`/) { eval($1) }
  # process line …
end

Retry
    for i in 1..100
      print "Now at #{i}. Restart? "
      retry if gets =~ /^y/i
    end
Running this interactively, you may see
    Now at 1. Restart? n
    Now at 2. Restart? y
    Now at 1. Restart? n
     …

Variable Scope, Loops, and Blocks
x = nil
y = nil
[ 1, 2, 3 ].each do |x|
  y=x+1
end
[ x, y ]   → [3, 4]

if false
  a=1
end
3.times {|i| a = i }
a        2

發表在 Ruby on Rails | 留下評論