Ruby on Rails實戰–創建一個網上商店E用戶管理模塊

本節創建商店的用戶管理系統. 創建存放用戶資料的數據表,加入添加,刪除用戶功能, 後台管理用戶權限審查功能,和用戶登錄 退出功能.
創建用戶model: depot> ruby script/generate model user
修改depot/db/migrate/007_create_users.rb文件內容如下:
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column :name, :string
      t.column :hashed_password, :string
      t.column :salt, :string #生成密碼hash用的salt
    end
  end

 
  def self.down
    drop_table :users
  end
end

應用depot> rake db:migrate

修改depot/app/models/user.rb文件內容如下:
require ‘digest/sha1′
#用來生成密碼hash值
class User < ActiveRecord::Base

#檢驗添加用戶表格
  validates_presence_of :name,
  :password,
  :password_confirmation
  validates_uniqueness_of :name
  validates_length_of :password,
  :minimum => 5,
  :message => "should be at least 5 characters long"
  attr_accessor :password_confirmation
  #自動"再輸入一次密碼"的檢驗
  validates_confirmation_of :password
 
  # ‘password’ 是一個 virtual attribute
  def password
    @password
  end
 
  def password=(pwd)
    @password = pwd
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end
 
  def self.authenticate(name, password)
    user = self.find_by_name(name)
    if user
      expected_password = encrypted_password(password, user.salt)
      if user.hashed_password != expected_password
        user = nil
      end
    end
    user
  end
 
  #安全刪除,當試圖刪除用戶表中最後一個用戶時rollback數據庫內容
  def safe_delete
    transaction do
      destroy
      if User.count.zero?
        raise "Can’t delete last user"
      end
    end
  end
 
  private
 
  def self.encrypted_password(password, salt)
    string_to_hash = password + "wibble" + salt
    Digest::SHA1.hexdigest(string_to_hash)
  end
 
  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end
end

生成Login controller
depot> ruby script/generate controller Login add_user login logout delete_user list_users
後面接的大堆都是login裡面的actions.
depot/app/controllers/login_controller.rb文件內容為:
class LoginController < ApplicationController
  #所有actions,除了login都要進行權限審查
  before_filter :authorize, :except => :login
  #加入admin的模板
  layout"admin"
 
  def index
    @total_orders = Order.count
  end
 
  def add_user
    @user = User.new(params[:user])
    if request.post? and @user.save
 #requset.post?用來檢驗request是否POST形式
      flash[:notice] = "User #{@user.name} created"
      @user = User.new
    end
  end
 
  def login
    session[:user_id] = nil
    if request.post?
      user = User.authenticate(params[:name], params[:password])
      if user
        session[:user_id] = user.id
        #如果原來頁面存在,返回原先頁面
        redirect_to(session[:original_url] || { :action => "index" })
      else
        flash[:notice] = "Invalid user/password combination"
      end
    end
  end
 
  def logout
    session[:user_id] = nil
    flash[:notice] = "Logged out"
    redirect_to(:action => "login")
  end
 
  def delete_user
    id = params[:id]
    if id && user = User.find(id)
      begin
   #安全刪除
        user.safe_delete
        flash[:notice] = "User #{user.name} deleted"
      rescue Exception => e
        flash[:notice] = e.message
      end
    end
    redirect_to(:action => :list_users)
  end
 
  def list_users
    @all_users = User.find(:all)
  end
end

修改depot/app/controllers/application.rb文件,添加用戶權限審查代碼:
class ApplicationController < ActionController::Base
  private
  def authorize
    unless User.find_by_id(session[:user_id])
      session[:original_uri] = request.request_uri #記住原來頁面
      flash[:notice] = "Please log in"
      redirect_to(:controller => "login", :action => "login")
    end
  end
end

向depot/app/controllers/admin_controller.rb文件加入審查要求:
class AdminController < ApplicationController
  before_filter :authorize

  #….

修改管理頁面使用的頁面模板depot/app/views/layouts/admin.rhtml,內容如下:
<html>
 <head>
  <title>Administer the Bookstore</title>
  <%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>
 </head>
 <body id="admin">
  <div id="banner">
   <img src="/images/logo.png"/>
   <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
   <div id="side">
    <p>
     <%= link_to "Products", :controller => ‘admin’, :action => ‘list’ %>
    </p>
    <p>
     <%= link_to "List users", :controller => ‘login’, :action => ‘list_users’ %>
     <br/>
     <%= link_to "Add user", :controller => ‘login’, :action => ‘add_user’ %>
    </p>
    <p>
     <%= link_to "Logout", :controller => ‘login’, :action => ‘logout’ %>
    </p>
   </div>
   <div id="main">
    <% if flash[:notice] -%>
     <div id="notice"><%= flash[:notice] %></div>
    <% end -%>
    <%= @content_for_layout %>
   </div>
  </div>
 </body>
</html>

添加用戶頁面depot/app/views/login/add_user.rhtml內容:
<div class="depot-form">
 <%= error_messages_for ‘user’ %>
 <fieldset>
  <legend>Enter User Details</legend>
  <% form_for :user do |form| %>
   <p>
    <label for="user_name">Name:</label>
    <%= form.text_field :name, :size => 40 %>
    <!–上面代碼自動生成input框–>
   </p>
   <p>
    <label for="user_password">Password:</label>
    <%= form.password_field :password, :size => 40 %>
   </p>
   <p>
    <label for="user_password_confirmation">Confirm:</label>
    <%= form.password_field :password_confirmation, :size => 40 %>
   </p>
   <%= submit_tag "Add User", :class => "submit" %>
  <% end %>
 </fieldset>
</div>

用戶登錄頁面depot/app/views/login/login.rhtml內容為:
<div class="depot-form">
 <fieldset>
  <legend>Please Log In</legend>
  <%= start_form_tag %>
  <!–form開始–>
   <p>
    <label for="name">Name:</label>
    <%= text_field_tag :name, params[:name] %>
   </p>
   <p>
    <label for="password">Password:</label>
    <%= password_field_tag :password, params[:password] %>
   </p>
   <p>
    <%= submit_tag "Login" %>
   </p>
  <%= end_form_tag %>
 </fieldset>
</div>

用戶主頁depot/app/views/login/index.rhtml內容:
<h1>Welcome</h1>
It’s <%= Time.now %>.
We have <%= pluralize(@total_orders,"order") %>.
<!–pluralize自動根據@total_orders的數量決定order使用單數還是複數形式–>

用戶列表頁面depot/app/views/login/list_users.rhtml內容:
<h1>Administrators</h1>
<ul>
 <%  for user in @all_users %>
  <li><%= link_to "[X]", { # link_to 參數
  #在用戶名前自動添加刪除用戶的鏈接
  :controller => ‘login’,
  :action => ‘delete_user’,
  :id => user},
  { # html 參數
  :post => true,
  :confirm => "Really delete #{user.name}?"
  } %>
  <%= user.name %>
  </li>
 <% end %>
</ul>

整理代碼:
在depot/app/controllers/store_controller.rb中加入:
  before_filter :find_cart, :except => :empty_cart
  def find_cart
    @cart = (session[:cart] ||= Cart.new)
  end
並刪除其它散雜的@cart賦值語句.

本節結束.

發表在 Ruby on Rails | 留下評論

Ruby on Rails實戰–創建一個網上商店D收銀台

上一節:Ruby on Rails實戰–創建一個網上商店C小試Ajax
本節完成收銀台功能. 為頁面新增一個結賬按鈕,用戶挑選商品後點擊結賬按鈕時出現一個用戶資料表單,用戶填交後,系統將商品信息和用戶信息保存到數據庫中.

創建order model
depot> ruby script/generate model order
修改depot/db/migrate/005_create_orders.rb 內容為:
class CreateOrders < ActiveRecord::Migration
  def self.up
    create_table :orders do |t|
      t.column :name, :string
      t.column :address, :text
      t.column :email, :string
      t.column :pay_type, :string, :limit => 10
    end
  end

  def self.down
    drop_table :orders
  end
end

創建line_item model,
depot>ruby script/generate model line_item
修改depot/db/migrate/006_create_line_items.rb文件內容為:
class CreateLineItems < ActiveRecord::Migration
  def self.up
    create_table :line_items do |t|
      t.column :product_id, :integer, :null => false
      t.column :order_id, :integer, :null => false
      t.column :quantity, :integer, :null => false
      t.column :total_price, :integer, :null => false
    end
 #創建兩個foreign key
    execute "alter table line_items
            add constraint fk_line_item_products
            foreign key (product_id) references products(id)"

    execute "alter table line_items
            add constraint fk_line_item_orders
            foreign key (order_id) references orders(id)"
  end
 
  def self.down
    drop_table :line_items
  end
end

向數據庫應用
depot> rake db:migrate

關聯model:
在depot/app/models/order.rb和
depot/app/models/product.rb兩文件者加入:
has_many :line_items
聲明這兩個model下有多個line_items
在depot/app/models/line_item.rb文件中加入:
belongs_to :order
belongs_to :product
聲明這個model從屬於order和product
*if a table has foreign keys, the corresponding model should have a belongs_to for each.

添加結賬按鈕:
在depot/app/views/store/_cart.rhtml文件:
<%= button_to "Empty cart", :action => :empty_cart %>
行上方加入:
<%= button_to "Checkout", :action => :checkout %>

checkout action
在depot/app/controllers/store_controller.rb文件中定義checkout action 和save_order action:
  def checkout
    @cart = find_cart
    if @cart.items.empty?
 #判斷籃中是否為空
      redirect_to_index("Your cart is empty")
    else
      @order = Order.new
    end
  end

  def save_order
    @cart = find_cart
    @order = Order.new(params[:order])
    @order.add_line_items_from_cart(@cart)
    if @order.save #保存數據
      session[:cart] = nil #清空購物籃
      redirect_to_index("Thank you for your order")
    else
      render :action => :checkout
    end
  end

相應 checkout 的view文件depot/app/views/store/checkout.rhtml內容為:
<div class="depot-form">
 <%= error_messages_for ‘order’ %>
 <fieldset>
  <legend>Please Enter Your Details</legend>
  <% form_for :order, :url => { :action => :save_order } do |form| %>
   <p>
    <label for="order_name">Name:</label>
    <%= form.text_field :name, :size => 40 %>
   </p>
   <p>
    <label for="order_address">Address:</label>
    <%= form.text_area :address, :rows => 3, :cols => 40 %>
   </p>
   <p>
    <label for="order_email">E-Mail:</label>
    <%= form.text_field :email, :size => 40 %>
   </p>
   <p>
    <label for="order_pay_type">Pay with:</label>
    <%=
     form.select :pay_type,
     Order::PAYMENT_TYPES,
     #這個下拉列表內容另定義
     :prompt => "Select a payment method"
    %>
   </p>
   <%= submit_tag "Place Order", :class => "submit" %>
  <% end %>
 </fieldset>
</div>
上面藍色的代碼用來組建form.

在depot/app/models/order.rb文件中定義上面下拉列表的PAYMENT_TYPES內容:
  PAYMENT_TYPES = [
  # 顯示文字 數據庫內容
  [ "Check", "check" ],
  ["Credit card", "cc" ],
  ["Purchase order", "po" ]
  ]
  #校驗用戶名,地址,信箱地址和支付方式是否為空
  validates_presence_of :name, :address, :email, :pay_type
  #校驗支付方式是否合法(加強安全性)
  validates_inclusion_of :pay_type, :in => PAYMENT_TYPES.map {|disp, value| value}
 
  #定義上面用到的add_line_items_from_cart()
   def add_line_items_from_cart(cart)
    cart.items.each do |item|
      li = LineItem.from_cart_item(item)
      line_items << li
    end
  end

修改depot/app/models/line_item.rb文件內容為:
class LineItem < ActiveRecord::Base
  belongs_to :order
  belongs_to :product
  def self.from_cart_item(cart_item)
    li = self.new
    li.product = cart_item.product
    li.quantity = cart_item.quantity
    li.total_price = cart_item.price
    li
  end
end

在depot/app/views/store/add_to_cart.rjs文件中加入:
page.select(‘div#notice’).each { |div| div.hide }
搜索頁面中id=notice的div,如有找到,將div隱藏.
在用戶結賬後繼續購物時隱藏結賬成功提示語.

本節結束

下一節:Ruby on Rails實戰–創建一個網上商店E用戶管理模塊

發表在 Ruby on Rails | 留下評論

Ruby on Rails實戰–創建一個網上商店C小試Ajax

上一節:Ruby on Rails實戰–創建一個網上商店B前台

本節將向商店加入一個Ajax購物籃,使商店產品列表在不刷新的情況下更新顯示購物籃信息

修改depot/app/controllers/store_controller.rb文件,如下:
  def index
    @products = Product.find_products_for_sale
    @cart = find_cart #加入對@cart的定義
  end
   def add_to_cart
    begin
      @product = Product.find(params[:id])
    rescue
      logger.error("Attempt to access invalid product #{params[:id]}")
      redirect_to_index("Invalid product")
    else

      @cart = find_cart
      @current_item = @cart.add_product(@product)
      redirect_to_index unless request.xhr?
   #request.xhr判斷是否xmlHttpRequest, 否將指向index action, 用來兼容關閉了javascript功能的瀏覽器
   #開發時以無Ajax的為藍本,再修改到ajax,以方便兼容性處理
    end
  end
  #….
  private
  def redirect_to_index(msg = nil)
#msg = nil 指定msg的默認值, 如果msg沒有說明, msg = nil.
    flash[:notice] = msg if msg
 #加入對無參數的支持
    redirect_to :action => :index
  end
  #…

修改depot/app/models/cart.rb文件,如下:
def add_product(product)
 current_item = @items.find {|item| item.product == product}
 if current_item
  current_item.increment_quantity
 else
  current_item = CartItem.new(product)
  @items << current_item
 end
 current_item #新加,使返回修改商品
end

修改depot/app/controllers/store_controller.rb文件,如下:
def add_to_cart
 begin
  @product = Product.find(params[:id])
 rescue
  logger.error("Attempt to access invalid product #{params[:id]}")
  redirect_to_index("Invalid product")
 else
  @cart = find_cart
  @current_item = @cart.add_product(@product) #新加,定義@current_item
 end
end
#….
  def empty_cart
    session[:cart] = nil
    redirect_to_index #清空購物籃後返回商品列表
  end
#…

修改depot/app/models/cart.rb文件,增加一個購物籃內商品數據變量
def total_items
 @items.inject(0) {|sum, item| sum + item.quantity}
end

在depot/app/views/store/index.rhtml
中將:
 <%= button_to "Add to Cart", :action => :add_to_cart, :id => product %>
改為:
  <%= form_remote_tag :url => { :action => :add_to_cart, :id => product } %>
        <%= submit_tag "Add to Cart" %>
        <%= end_form_tag %>
 
在depot/app/views/layouts/store.rhtml文件里加入模板對javascript的支持,如下:
<html>
 <head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "depot", :media => "all" %>
  <%= javascript_include_tag :defaults %>
 </head>

在depot/app/views/store/新加一個partial template _cart.rhtml,內容如下:
<div class="cart-title">Your Cart</div>
<table>
 <%= render(:partial => "cart_item", :collection => cart.items) %>
 <!–調用另一個partial template _cart_item.rhtml–>
 <tr class="total-line">
  <td colspan="2">Total</td>
  <td class="total-cell"><%= format_price(cart.total_price) %></td>
 </tr>
</table>
<%= button_to "Empty cart", :action => :empty_cart %>
partial template以下找線開頭,由render的調用.

在depot/app/views/store/新加一個partial template _cart_item.rhtml,內容如下:
<% if cart_item == @current_item %>
<!–後面用來顯示特殊效果–>
 <tr id="current_item">
 <% else %>
 <tr>
<% end %>
  <td><%= cart_item.quantity %>&times;</td>
  <td><%= h(cart_item.title) %></td>
  <td class="item-price"><%= format_price(cart_item.price) %></td>
 </tr>

在depot/app/views/layouts/store.rhtml文件中增加調用partial template的代碼:
   <div id="side">
                <%= hidden_div_if(@cart.items.empty?, :id => "cart") %>
    <!–hidden_div_if 這個 helpper method用來向div加入display:none屬性, 代碼見下文–>
                    <%= render(:partial =>"cart", :object => @cart) %>
                </div>
    …..

創建hidden_div_if  helpper method
  def hidden_div_if(condition, attributes = {})
    if condition
      attributes["style"] = "display: none"
    end
    attrs = tag_options(attributes.stringify_keys)
    "<div #{attrs}>"
  end

刪除不用了的add_to_cart.rhtml

新建depot/app/views/store/add_to_cart.rjs文件,內容如下:
page[:cart].replace_html :partial => ‘cart’, :object => @cart
#將頁面中id=cart的元素換成partial _cart.rhtml的內容
page[:cart].visual_effect :blind_down if @cart.total_items == 1
#當向購物籃添加第一個商品時,特效顯示出購物籃
page[:current_item].visual_effect :highlight,
               :startcolor =>"#88ff88",
               :endcolor =>"#114411"
#當購物籃商品發生變化時,特效顯示變化行

本節完成,為使ajax效果生效, 我重新啟動了服務器

下一節:Ruby on Rails實戰–創建一個網上商店D收銀台

本文最後更新 20070108

發表在 Ruby on Rails | 留下評論

想對越劇學生說的心裡話–門外看越劇的派別

1.首先,我是一個新喜歡上越劇的人.我分不清越劇的派別, 但我打心底覺得越劇很美, 我希望它能重新流行起來.
2.我覺得問題的重點是怎樣讓越劇更好聽, 讓更多的人歡迎. 這是最終的目標. 學越劇的最終目標不是學的最像誰, 而是怎樣才能受觀眾的喜愛.不能本未倒置.
3.觀眾是指大眾,特別是現在不喜歡越劇的年青人, 而不是現在已經存在的少數越劇迷. 已經存在的越劇迷本來就不多, 而且他們越來越少. 新學越劇的人不應該只為這些人學越劇, 而應該面向大眾. 如果這些老越劇迷(應該大多是老的吧)說你學的不像誰或誰, 1.對他們不要憐憫,因為他們還有大把老唱片 2.於自己,不用太在意他們的評價, 因為他們會慢慢離去.
4.世上本沒有派別, 但人和人總是不同的, 一個演員唱了幾十年, 自然會形成自己的風格. 這風格和演員生理和人世經歷息息相關. 當崇拜者說她是什麼什麼"派"時, 將心比心, 如果那個老演員, 你或也會飄飄然, 然後你也會放不下這個稱號, 於是或你也會有意無意地讓你的學生為你傳承技術(或更應該說聲譽).但你的生理和人世經歷和她的一定不同,這樣的傳承不自然. 
5.我不是說不能從前輩學習到什麼, 我的意思是重學"道"輕學"術", 而不顰"形".
6.忘記派別, 把派別簡單地看成前人不同的風格, 以聽眾為本, 凡美的我就學, 我就吸收, 當然這"美"是主觀的,而這主觀有對有錯, 於是你不會受天下人都喜歡, 但那個高人能受天下人喜歡呢? 
7.願越劇演員青出於藍而勝於藍, 願有一天老唱片不再流行和值錢!

發表在 越劇柔情 | 留下評論

Ruby語言入門

1.Ruby是一個面向對象的(object-oriented)的編程語言.
Ruby中所有的操作元都是對象(object).
類(Class),方法(method),實例(instance),對象(object, class instance), constructor, instance variable, instance method, –當自然語言學家遇上程序語言…
method實例:
"dave".length
line_item_one.quantity
-1942.abs
cart.add_line_item(next_purchase)

2.命名

局部變量,method參數和method名以小寫字母或下劃線開頭.實例變量以@號開頭.多單詞名最好以下劃線分隔單詞
實例: line_item
Class名,module名,常量以大寫字母開頭. 最好以大寫字母分隔不同單詞.如: PurchaseOrder
Symbols如: redirect_to :action => "edit", :id => params[:id]
用來指定值. ???

3.Method
實例:
def say_goodnight(name)
 result = "晚安, " + "#{name.capitalize}"
 return result
end
#該道別了…
puts say_goodnight("小李")
puts (say_goodnight("王老闆"))

Ruby語句每句一行,每行結束不用任何符號
+可以用來連接字符串
注釋語句以#開頭
使用def定義method
puts method用來調用method,將結果顯示在平台上.
雙引號字符串內的轉意字符(如
)和變量名(上面的#{name}及其method capitalize())將被解釋,單引號內字符串則不被解釋.
Ruby自動返回method中最後一個表達式的值. 上method等於:
def say_goodnight(name)
 "晚安, #{name.capitalize}"
end
puts say_goodnight("小李")

4.Class
class Order < ActiveRecord::Base
#class 類名 < 子model ::主class名 (定義聲明和從屬聲明)
 has_many :line_items

 def self.find_all_unpaid
 #使用 self.前綴,定義class method (相對於instance method)
 #可在程序中任意調用Order.find_all_unpaid
  find(:all, ‘paid = 0′)
 end

 def total
 #定義instance method
 #調用時應用到實例對象上
 #如puts "總數是#{order.total)",注意這個小寫的order
  sum = 0
  line_items.each {|li| sum += li.total}
 end
end

關於instance變量
class Greeter
 def initialize(name)
  @name = name
  # instance變量以@開頭
  #變量@name只能在類內調用
 end
 def say(phrase)
  puts "#{phrase},#{@name}"
 end
end

g1 = Greeter.new("小李")
g2 = Greeter.new("王老闆")

g1.say("好啊")  #=> 老啊,小李
g2.say("早啊")  #=> 早啊,王老闆

如要將Greeter里的name在外部調用,要用以下方法:
Class Greeter
 def initialize(name)
  @name = name
 end
 def name
  @name
 end
 def name=(new_name)
 #???
  @name = new_name
 end
end

g = Greeter.new("小李")
puts g.name #=>小李
g.name = "王老闆"
puts g.name #=> 王老闆
方便實現上面功能的代碼:
class Greeter
 attr_accessor :name #可讀可寫
 attr_reader :name #只可讀
 attr_writer :name #只可寫

Private和Protected
Private methods只能在同instance內調用
Protected methods除了可在同instance內調用, 也可在類或子類內調用

5.Module
Module和Class類似,是一個常量,method,module和class集. 不同的是不能用Module來創建object.
Module的作用:
1.產生namespace
2.分享class間的功能,沒繼承效果
多個class可以共用一個module,一個class也可使用多個module.

Rails還使用module產生helper method, 輔助應用到view.

6. Array 和Hash
Array和Hash 都是一個數組. Array的索引是整數, 而Hash的索引可以是object. Array的效率相對比Hash高.
Array和Hash都可包含不同類型的變量
Array實例:
a = [1, '狗狗', 3.14] #新數組
a[0] #調用(1)
a[2] #調用(nil, 在Ruby中nil是一個object,指代nothing)
#只有nil和false才等同於邏輯"否". 0為true

又一實例說明<<的用法:
ages = [] #定義新數組
for person in @people
 ages << person.age #<<將數值追加到數組中去
end

又又一個實例說明自動生成單詞數組的用法:
a = ['ant', 'bee', 'cat', 'dog', 'elk']
a = %w{ ant bee cat dog elk }

Hash實例:
inst_section = {
 :高手 => ‘小張’,
 :新來的 => ‘小李’,
 :老闆 => ‘王老闆’
}
#調用
inst_section[:高手] #=>’小張’
inst_section[:最討厭的] #=>nil
左邊的symbols是索引,右邊的是值,索引不能重複
值可以另一個array或hash
當hash是method的最後一個參數時,可以省略括號,如:
redirect_to :action => ‘show’, :id => product.id

7.流控制
if實例:
if count > 10
 puts "再來一次"
elseif
 "你輸 了"
else
 "輸入一個數字"
end
while實例:
while weight < 100 and num_pallets <= 30
 pallet = next_pallet()
 weight += pallet.weight
 num_pallets += 1
end
表達式簡化式實例:
puts "早上好" if time < a

8.正則表達式
寫法 /pattern/ 或 %r{pattern}
用法實例:
if line =~ /P(erl|ython)/ #用這個來查找匹配
 puts "這個不怎麼樣吧?"
end
正則小例:
/ab+c/ a跟着多個或一個b,後面接c

9.Block 和 Iterator
一行的Block實例:
{ puts "你好" }
多行的Block實例:
do
 club.enroll(person)
 person.socialize
end
Block的用法實例:
greet { puts "嗨" }
放在method後,如有參數,block放到參數後,如:
verbose_greet("王五","老闆") { puts "嗨" }

iterator is a method that returns successive elements from some kind of collection, such as an array.
Block 和 Iterator聯合使用實例:
animals = %w( ant bee cat dog elk )
animals.each { |animal| puts animal }
#animals.each會yield出後面的block. 本身的值會經|animal|傳給block.
所有的整數帶有times() method, 使用:
3.times { print "哇! " }

10.意外處理
begin
 content = load_blog_data(file_name)
rescue BlogDataNotFound
 STDERR.puts "#{file_name}文件沒有找到"
rescue BlogDataFormatError
 STDERR.puts "#{file_name}文件數據無效"
rescue Exception => exc
 STDERR.puts "讀取#{file_name}文件出錯:#{exc.message}"
end

11.Marshaling Objects
將object 轉換成數據流,方便移動.

12. 互交Ruby

13.慣用形式
empty! Bang method( normally do something destructive to the receiver)
empty? 判斷
a || b 如果a為false或nil, 則返回 b, 否則返回a.
a ||= b a = a || b
a += 1 a = a +1
a *= 5 a = a * 5
* 對於大部分操作:a op= b a = a op b

發表在 Ruby on Rails | 留下評論

Ruby語言簡介

Ruby是一種面向對象(object-oriented)的計算機編程語言.由日本人松本行弘(Yukihiro "Matz" Matsumoto)於1993年發明.
Ruby語言簡介
Ruby之父 松本行弘(Matsumoto Yukihiro)

松本行弘認為以往人們在開發編程語言時過於看重"計算機", 而忽視"人", 過分強調運行速度. 而松本行弘提倡機器不是主人,是工具,而真正的主人應該是"人", 於是他打算開發一種更人性化的編程語言,這就是後來的Ruby.
松本行弘還提出語言不但是表達思想的工具,也是人類進行思想的方法,使用的語言不同, 人也會產生不同的思想模式. 松本行弘說編程語言也會產生類似的作用. 他認為一個好的編程語言不但應該可以執行程序任務, 也應該幫助程序員形成更好的編程邏輯.
松本行弘也強調編程語言應該不單讓程序員帶來工資,也要給他們帶來樂趣.
ruby語言官方主頁:
http://www.ruby-lang.org/
松本行弘談ruby設計原則(英語錄音):
http://www.itconversations.com/shows/detail1638.html

發表在 Ruby on Rails | 留下評論

一個人的舞台–評徐標新等2004年錄的越劇<珍珠塔>

一山一峰不同嶺
一花一草各有心
原天常生好心人
願人常做好事情

一個人的舞台--評徐標新等2004年錄的越劇<珍珠塔>

剛開始出場就不對,馬上上網搜索,果然,徐標新是個男的!!!
這是第一個意外, 漸漸我發現一個更可怕的事–這部越劇是他一個人的戲.
說實話,方夫人雖然操一口地道的上海音,但唱的不錯.
方小姐實在不敢恭維,我似乎永遠不能捉摸她發出的下一個音是什麼調的.
方老爺也是男的, 這回讓我意外的不是他的性別,而是他的功底. 雖然很小心,但為什麼要上台呢?

排除其他演員的全力鋪墊, 我想徐標新也會是一個很優秀的演員. 特別是最後那段道情, 太美了.
但我沒有被說服: 為什麼??? 難道越劇真的要這樣發展嗎?

發表在 越劇柔情 | 留下評論

Ruby on Rails實戰–創建一個網上商店B前台

上一節: Ruby on Rails實戰–創建一個網上商店a
本節創建商店的前台模塊, 也就是客戶看到的頁面.

1.創建前台Controller Store:depot> ruby script/generate controller store index
最後的index創建一個index Action,用作默認action

2.創建一個session,用來保存購物籃數據
depot> rake db:sessions:create
然後
depot> rake db:migrate
(users of Rails applications must have cookies enabled in their browsers.???)
在config/environment.rb中將
config.action_controller.session_store = :active_record_store
語句前的註解符#去除,啟動數據庫保存session功能
*使用depot> rake db:sessions:clear可以清空當前session內容

3.創建前台的Store的Controller
修改depot/app/controllers/store_controller.rb文件為
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
class StoreController < ApplicationController
  def index
    @products = Product.find_products_for_sale
  end
  #find_products_for_sale將在model裡面定義,見下文
  #下面是購物籃添加程序
  def add_to_cart
    begin
      @product = Product.find(params[:id])
    rescue
      logger.error("Attempt to access invalid product #{params[:id]}")
      redirect_to_index("Invalid product")
    else
      @cart = find_cart
      @cart.add_product(@product)
    end
  end
  #上面的begin…rescue…else…end用來處理錯誤
  #當begin出錯,即找不到當前ID的商品時進行rescue處理,以防止入侵或意外出錯
  #上面的logger.eeror用來記錄錯誤log,對應log目錄里的development.log文件
  # @product = Product.find(params[:id])可以接 add_to_cart/1 樣式傳來的request.
  #上面的redirect_to_index見下面代碼
  #上面的find_cart見下面代碼
  #add_product()代碼見下面.

  #下面是購物籃清空程序
  def  empty_cart
    session[:cart] = nil
    redirect_to_index("Your cart is currently empty")
  end

  private #開始定義局部代碼

#一個高壓縮處理了的錯誤信息顯示代碼
  def redirect_to_index(msg)
    flash[:notice] = msg #用來顯示出錯信息
    redirect_to :action => :index
  end
#flash[:notice] = msg #用來顯示flash信息
#redirect_to :action => :index 可用來轉移頁面.

#使用session來保存購物籃數據
  def find_cart
    session[:cart] ||= Cart.new
  end
end
#上面的||=語句用來創建檢查session,如果存在則調出數據,如果不存在生成新session
#!!!好符號化的語言啊!!!日本人不太懂英語吧.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

4.創建model:
修改depot/app/models/product.rb文件為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
class Product < ActiveRecord::Base
  def self.find_products_for_sale
    find(:all, :order => "title")
  end
 #用 self.前綴,定義class method
  #上面的find(:all, :order => "title")讓程序列出所有商品,按標題排序
  #以下為原來的效驗代碼….
end
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

手動創建一個depot/app/models/cart.rb, 作為購物籃的model,內容如下:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
class Cart
  include Reloadable #手動創建的model要加入這句,以後服務器才會自動刷新
  #Whenever youcreatea non-database model, youneed toinclude a includeReloadable directive in the source.
  attr_reader :items 
  def initialize #初始化method
    @items = [] # @items = []來賦空集.
  end
  def add_product(product)
    existing_product = @items.find {|item| item.product == product}
    if existing_product #如果籃中已有商品,累加數量
      existing_product.increment_quantity
    else
      @items << CartItem.new(product)
    end
  end
  def total_price
    @items.inject(0) { |sum, item| sum + item.price }
  end
end
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

手動創建一個depot/app/models/cart_item.rb model,用來處理購物籃內的商品,內容如下:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
class CartItem
  include Reloadable #見上文
  attr_reader :product, :quantity
  def initialize(product)
    @product = product
    @quantity = 1
  end
  def increment_quantity
    @quantity += 1
  end
  def title
    @product.title
  end
  def price
    @product.price * @quantity
  end
end
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

5.創建View:
修改depot/app/views/store/index.rhtml文件為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<% for product in @products -%>
 <div class="entry">
  <img src="<%= product.image_url %>"/>
  <h3><%= h(product.title) %></h3>
  <%= product.description %>
  <span class="price"><%= format_price(product.price) %></span>
  <%= button_to "Add to Cart", :action => :add_to_cart, :id => product %>
 </div>
 <br />
<% end %>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*上面的product.description為使描述帶有HTML代碼,沒有使用h(),帶有安全隱患.
*上面的format_price為一個helper,來用格式化整數形的價格.見下文.
*上面的button_to將生成一個按鈕,鏈接到add_to_cart action,用於向購物籃添加商品,它將以post方向向add_to_cart action傳送商品ID信息. (post比get好???)
(And a POST request is just the ticket when we want to do something like add an item to a cart.)
*button_to的作用實際上相應於生成如下代碼:
<form method="post" action="/store/add_to_cart/1" class="button-to">
<input type="submit" value="Add to Cart" />
</form>

手動建立一個添加商品頁面的view depot/app/views/store/add_to_cart.rhtml,文件內容如下:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<div class="cart-title">Your Cart</div>
<table>
 <% for cart_item in @cart.items %>
  <tr>
   <td><%= cart_item.quantity %> &times;</td>
   <td><%= h(cart_item.title) %></td>
   <td class="item-price"><%= format_price(cart_item.price) %></td>
  </tr>
 <% end %>
 <tr class="total-line">
  <td colspan="2">Total</td>
  <td class="total-cell"><%= format_price(@cart.total_price) %></td>
 </tr>
</table>
<%= button_to "Empty cart", :action => :empty_cart %>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* &times;生成一個乘號.

6.增加format_price helper
修改depot/app/helpers/store_helper.rb文件為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
module StoreHelper
  def format_price(amount)
    dollars, cents = amount.divmod(100)
    sprintf("$%d.%02d", dollars, cents)
  end
end
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*上面的divmod是一個內置方法. 用它將以分為單位的整數形價格分為元和分兩部分.

7.給view添加一個模板
修改:depot/app/views/layouts/store.rhtml文件內容為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<html>
 <head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "depot", :media => "all" %>
 </head>
 <body id="store">
  <div id="banner">
   <img src="/images/logo.png"/>
   <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
   <div id="side">
    <a href="http://www….">Home</a><br />
    <a href="http://www…./faq">Questions</a><br />
    <a href="http://www…./news">News</a><br />
    <a href="http://www…./contact">Contact</a><br />
   </div>
   <div id="main">
    <!–下面的代碼顯示錯誤提示信息–>
    <% if flash[:notice] -%>
     <div id="notice"><%= flash[:notice] %></div>
    <% end -%>
    <!–下面的代碼顯示不同action的子view內容–>
    <%= @content_for_layout %>
    <!–其它的內容為共用模板–>
   </div>
  </div>
 </body>
</html>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*這個和controller同名的layout文件為view的默認模板.
*<%= @page_title || "Pragmatic Bookshelf" %> ???

到這裡用戶界面已經基本完成.
調試使用 http://localhost:3000/store/訪問

下一節:Ruby on Rails實戰–創建一個網上商店C小試Ajax

發表在 Ruby on Rails | 一條評論

Ruby on Rails實戰–創建一個網上商店a

這是一個使用Ruby on Rails創建一個網上商店的實例. 實例來自<Agile Web Development with Rails>第二版 beta. 下面是我整理的筆記. 筆記對實例進行了註解, 記錄我的學習路程, 同在學習Ruby on Rails的朋友可作為參考. 如果裡面有什麼錯誤,還請留言指正.
按學習日程,我把這個實例分為幾段, 分別完成: 網上商店基本構架 Ruby語言入門

這是第一部分, 完成商店的基本構架.

首先要在準備好實例的學習環境, 參考: 在Windows平台上學習Ruby on Rails 的環境準備

1.it’s easier to throw something away if you didn’t spend a long time creating it.
2.使用筆+紙打草圖以加快速度.

以下的命令都是在ruby on rails的命令輸入窗進行的.
3.項目代號Depot,創建相應項目:work> rails depot
4.創建mysql數據庫depot_development:
depot> mysqladmin -u root create depot_development
注意mysql的用戶名和密碼.
數據庫測試:depot> rake db:migrate
不顯示錯誤提示為正常.
rake db:migrate也用來應用數據庫的修改, 以後會經常用到.

下面開始創建後台功能

5.創建model product:depot> ruby script/generate model Product
生成的文件名001_create_products.rb中的001為版本號.
修改db/migrate/001_create_products.rb內容為:
—————————————————————————
class CreateProducts < ActiveRecord::Migration
  def self.up
    create_table :products do |t|
      t.column :title, :string
      t.column :description, :text
      t.column :image_url, :string
    end
  end
  def self.down
    drop_table :products
  end
end
—————————————————————————
使用rake命令應用數據庫:depot> rake db:migrate
後面的:string是數據類型,常用的數據類型還有:text,integer,time…

7.創建Controller admin:depot> ruby script/generate controller admin
修改depot/app/controllers/admin_controller.rb內容為:
class AdminController < ApplicationController
 scaffold :product
end
scaffold是rails的一個內建model框架.
現在啟動服務器(depot> ruby script/server)調試,後台功能已經基本實現.
調試方法請參看: 網上商店基本構架  Ruby語言入門

這是第一部分, 完成商店的基本構架.

首先要在準備好實例的學習環境, 參考: Ruby on Rails入門 –寫第一個程序

8.向數據庫追加字段price
生成追加文件:depot> ruby script/generate migration add_price
修改文件depot/db/migrate/002_add_price.rb內容為:
—————————————————————————–
class AddPrice < ActiveRecord::Migration
  def self.up
    add_column :products, :price, :integer, :default => 0
  end
  def self.down
    remove_column :products, :price
  end
end
—————————————————————————-
*可以使用:default=>0為price字段設置默認值.
可用參數:
default=>0設定默認值
null=>false設定不能為空
limit => 10
應用數據庫改變:depot> rake db:migrate

9.為數據輸入增加校驗功能
修改depot/app/models/product.rb為:
——————————————————————————-
class Product < ActiveRecord::Base
  validates_presence_of :title, :description, :image_url
  validates_numericality_of :price, :only_integer => true
  protected
  def validate
    errors.add(:price,"should be positive") if price.nil? || price <= 0
  end

  validates_uniqueness_of :title
  validates_format_of :image_url,
  :with => %r{\.(gif|jpg|png)$}i,
  :message =>"must be a URL for a GIF, JPG, or PNG image"
end
——————————————————————————-
*其中validates_presence_of指定字段輸入不能為空.
*validates_numericality_of指定字段為數字(浮點數)
*  protected
  def validate
    errors.add(:price,"should be positive") if price.nil? || price <= 0
  end

  讓price字段不為空,且大於0,否則顯示"price should be positive"提示.
  protected參見: 網上商店基本構架  Ruby語言入門

這是第一部分, 完成商店的基本構架.

首先要在準備好實例的學習環境, 參考: Ruby語言入門

validate???
*validates_uniqueness_of指定字段不能有重複內容
*validates_format_of和後面的正則表達式限制圖片路徑指向指定格式的圖片文件.
其它:
  validates_length_of :name, :within => 6..100 指定字段長度取值範圍
  validates_length_of :content, :minimum => 10  指定長度最小值
  validates_associated :bliki ????

10.以腳本方式向數據庫追加內容
創建新migration: depot> ruby script/generate migration add_test_data
修改depot/db/migrate/003_add_test_data.rb文件內容為:
——————————————————————————————-
class AddTestData < ActiveRecord::Migration
  def self.up
    Product.create(:title =>’Pragmatic Version Control’,
    :description =>
%{<p>This book is a recipe-based approach to using Subversion that will get you up and running quickly–and correctly. All projects need’s a foundational piece of any project’s version control: it infrastructure. Yet half of all project teams in the U.S. don’t use any version control at all. Many others don’t use it well, and end up experiencing time-consuming problems.</p>},
    :image_url =>’/images/svn.jpg’,
    :price => 2850)
    # . . .
  end
  def self.down
    Product.delete_all
  end
end
————————————————————————————————
使用rake db:migrate命令應用到數據庫

10.美化商品列表
分離出scaffold代碼:depot> ruby script/generate scaffold product admin
scaffold為rails提供的內建動態功能,使用上面的語句將代碼分離出來,以便修改.
分離過程需要按兩次"y"確認.
depot/app/controllers/admin_controller.rb文件被修改
修改depot/app/views/layouts/admin.rhtml文件,將
<%= stylesheet_link_tag ‘scaffold’ %>
修改為:
<%= stylesheet_link_tag ‘scaffold’, ‘depot’ %>
這會將網站使用的CSS文件由默認的scaffold.css指向depot.css文件.
在public/stylesheets目錄下新建depot.css文件,內容為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/*Global styles*/
#notice {
border: 2px solid red;
padding: 1em;
margin-bottom: 2em;
background-color:#f0f0f0;
font: bold smaller sans-serif;
}
/*Styles for admin/list */
#product-list .list-title {
color: #244;
font-weight: bold;
font-size: larger;
}
#product-list .list-image {
width: 60px;
height: 70px;
}
#product-list .list-actions {
font-size: x-small;
text-align: right;
padding-left: 1em;
}
#product-list .list-line-even {
background:#e0f8f8;
}
#product-list .list-line-odd {
background:#f8b0f8;
}
/* Styles for main page */
#banner {
background:#9c9;
padding-top: 10px;
padding-bottom: 10px;
border-bottom: 2px solid;
font: small-caps 40px/40px "Times New Roman", serif;
color:#282;
text-align: center;
}
#banner img {
float: left;
}
#columns {
background:#141;
}
#main {
margin-left: 15em;
padding-top: 4ex;
padding-left: 2em;
background: white;
}
#side {
float: left;
padding-top: 1em;
padding-left: 1em;
padding-bottom: 1em;
width: 14em;
background:#141;
}
#side a {
color:#bfb;
font-size: small;
}
h1 {
font: 150% sans-serif;
color:#226;
border-bottom: 3px dotted #77d;
}

/*And entry in the store catalog*/
#store .entry {
border-bottom: 1px dotted #77d;
}
#store .title {
font-size: 120%;
font-family: sans-serif;
}
#store .entry img {
width: 75px;
float: left;
}
#store .entry h3 {
margin-bottom: 2px;
color:#227;
}
#store .entry p {
margin-top: 0px;
margin-bottom: 0.8em;
}
#store .entry .price-line {
}
#store .entry .add-to-cart {
position: relative;
}
#store .entry .price {
color:#44a;
font-weight: bold;
margin-right: 2em;
float: left;
}

/*Styles for the cart in the main page and the sidebar*/
.cart-title {
font: 120% bold;
}
.item-price, .total-line {
text-align: right;
}
.total-line .total-cell {
font-weight: bold;
border-top: 1px solid #595;
}
/* Styles for the cart in the sidebar */
#cart, #cart table {
font-size: smaller;
color: white;
}
#cart table {
border-top: 1px dotted #595;
border-bottom: 1px dotted #595;
margin-bottom: 10px;
}
/*Styles for order form*/
.depot-form fieldset {
background:#efe;
}
.depot-form legend {
color:#dfd;
background:#141;
font-style: sans-serif;
padding: 0.2em 1em;
}
.depot-form label {
width: 5em;
float: left;
text-align: right;
margin-right: 0.5em;
display: block;
}
.depot-form .submit {
margin-left: 5.5em;
}

/*The error box*/
.fieldWithErrors {
padding: 2px;
background-color: red;
display: table;
}

#errorExplanation {
width: 400px;
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: 12px;
margin: -7px;
background-color:#c00;
color:#fff;
}
#errorExplanation p {
color:#333;
margin-bottom: 0;
padding: 5px;
}
#errorExplanation ul li {
font-size: 12px;
list-style: square;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
這個文件包含整站的CSS代碼.

修改depot/app/views/admin/list.rhtml文件內容為:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<div id="product-list">
 <h1>Product Listing</h1>
 <table cellpadding="5" cellspacing="0">
  <% for product in @products %>
   <tr valign="top" class="<%= cycle(‘list-line-odd’, ‘list-line-even’) %>">
    <td>
     <img class="list-image" src="<%= product.image_url %>"/>
    </td>
    <td width="60%">
     <span class="list-title"><%= h(product.title) %></span><br />
     <%= h(truncate(product.description, 80)) %>
    </td>
    <td class="list-actions">
     <%= link_to ‘Show’, :action => ‘show’, :id => product %><br/>
     <%= link_to ‘Edit’, :action => ‘edit’, :id => product %><br/>
     <%= link_to ‘Destroy’, { :action => ‘destroy’, :id => product },
     :confirm =>"Are you sure?",
     :post => true
%>
    </td>
   </tr>
  <% end %>
 </table>
</div>
<%= if @product_pages.current.previous
 link_to("Previous page", { :page => @product_pages.current.previous })
end
%>
<%= if @product_pages.current.next
 link_to("Next page", { :page => @product_pages.current.next })
end
%>
<br />
<%= link_to ‘New product’, :action => ‘new’ %>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
系統自動提供@products變量.
手動創建的方法是:
在controller里字義@products = Product.find_products_for_sale
在Product類(models/product.rb)里定義:
class Product < ActiveRecord::Base
  def self.find_products_for_sale
    find(:all, :order => "title")
  end
  #….
 用 self.前綴,定義class method
*h(string) 用來處理html符號.
*class=cycle(‘樣式名1′,’樣式名2′)是一個helper method,用於在連續的行之間交互不同的樣式.
*truncate(‘字串’,長度數值)用來截取字符
*link_to用法 link_to ‘鏈接標題’, :action => ‘action名’, :id => product
*link_to ’Destroy’後面的:confirm =>"Are you sure?"會為頁面加入一個刪除確認提示.
* :post => true強制rails使用post方式傳輸數據,這個方式比get方式更適合用來做"刪除數據"鏈接

使用http://localhost:3000/admin/ 地址訪問調試.

本節結束.
下一節:
網上商店基本構架  Ruby語言入門

這是第一部分, 完成商店的基本構架.

首先要在準備好實例的學習環境, 參考: Ruby on Rails實戰–創建一個網上商店B前台

發表在 Ruby on Rails | 一條評論

Ruby on Rails入門 –寫第一個程序

寫之前要安裝好環境, 如果是windows請參看:

在Windows平台上學習Ruby on Rails 的環境準備

linux參看:

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

mac參看:

從Ubuntu轉到Mac OS X

所有命令行在Ruby Console Window里輸入.

1.創建一個程序:work> rails demo
2.啟動內建的WEBrick服務器:demo> ruby script/server
WEBrick是用來調測ROR程序的理想Web服務器. 這個服務器定時刷新訪問服務器文件內容,方便調試.
如WEBrick非默認服務器,使用demo>ruby script/server webrick可以強制啟動這個服務器.
啟動後可用http://localhost:3000地址訪問.
3.URL解釋:
http://localhost:3000/demo/say/hello
相應功能如下:
http://域名/程序/Controller/Action

4.創建一個Controller: demo> ruby script/generate controller Say
修改相應文件/demo/app/controllers/say_controller.rb為
class SayController < ApplicationController
 def hello
 end
end
*使用def 定義Action
5.創建相應模板文件/demo/app/views/say/hello.rhtml
文件內容:
<html>
 <head>
  <title>Hello, Rails!</title>
 </head>
 <body>
  <h1>Hello from Rails!</h1>
 </body>
</html>
rhtml文件是ERb(Embedded Ruby)文件格式. 在調用時Rails將解釋裡面的Ruby語句.
如:
<ul>
 <li>Addition: <%= 1+2 %> </li>
 <li>Concatenation: <%= "cow" + "boy" %> </li>
 <li> 1.hour.from_now</li>
 <li>Time in one hour: <%= 1.hour.from_now %> </li>
</ul>
可訪問http://localhost:3000/say/hello查看效果.

中的<%=…%>內容將被解釋.

*<%=…%>和VBScript的功能相似.

為了使<%=…%>之間的內容不帶有HTML特殊符號,加強代碼安全性,可使用h()將特殊字符進行處理,如:
Email: <%= h("Ann & Bill <frazers@isp.email>") %>
上面的處理效果是:
Email: Ann &amp; Bill &lt;frazers@isp.email&gt;

通常的Ruby語句放在<%…%>內,如:
<% 3.times do %>
 Ho!<br />
<% end %>
Merry Christmas!

但會形成多餘的換行符,可以使用<%…-%>解決這個問題.
如:
<% 3.times do -%>
 Ho!<br />
<% end -%>
Merry Christmas!

6.讓頁面顯示動態內容
修改/demo/app/controllers/say_controller.rb為:
class SayController < ApplicationController
 def hello
  @time = Time.now
 end
end

修改/demo/app/views/say/hello.rhtml為:
<html>
 <head>
  <title>Hello, Rails!</title>
 </head>
 <body>
  <h1>Hello from Rails!</h1>
  <p>
   It is now <%= @time %>
  </p>
 </body>
</html>

*使用@time定義變量

將代碼和模板最大可能分離,以加強代碼的靈活度.
7.創建鏈接
修改/demo/app/controllers/say_controller.rb,加入googby action.如:
class SayController < ApplicationController
 def hello
  @time = Time.now
 end
 def goodbye
 end
end
新建Googbye action的相應模板
/demo/app/views/say/goodbye.rhtml,內容為:
<html>
 <head>
  <title>See You Later!</title>
 </head>
 <body>
  <h1>Goodbye!</h1>
  <p> 
   It was nice having you here.
  </p>
  <p>
   Say <%= link_to "Hello", :action => "hello" %> again.
  </p>
 </body>
</html>

*<%= link_to "Hello", :action => "hello" %> 用來創建一個指向hello action的連接.
link_to是一個"方法",也可以將後面的參數加上括號.
第一個Hello是要顯示的字符,後面一個hello是鏈接的目標action,因為在同一Controller之內,省略Controller參數.
8.在命令台按Ctrl+C終止WEBrick服務器.結束本章.

發表在 Ruby on Rails | 19 條評論