作者归档:船长

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 条评论