分类目录归档: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 | 留下评论