分类目录归档:Ruby on Rails

US States List for Ruby on Rails

def select_state_for_user
       [["","Select State..."], ["AL","Alabama"],
        ["AK","Alaska"], ["AZ","Arizona"], ["AR","Arkansas"],
        ["CA","California"], ["CO","Colorado"], ["CT","Connecticut"],
        ["DE","Delaware"], ["DC","District of Columbia"],
["FL","Florida"],

        ["GA","Georgia"], ["HI","Hawaii"], ["ID","Idaho"],
["IL","Illinois"],
        ["IN","Indiana"], ["IA","Iowa"], ["KS","Kansas"],
["KY","Kentucky"],
        ["LA","Louisiana"], ["ME","Maine"], ["MD","Maryland"],
        ["MA","Massachusetts"], ["MI","Michigan"], ["MN","Minnesota"],
        ["MS","Mississippi"], ["MO","Missouri"], ["MT","Montana"],
        ["NE","Nebraska"], ["NV","Nevada"], ["NH","New Hampshire"],
["NJ","New
        Jersey"], ["NM","New Mexico"], ["NY","New York"], ["NC","North
        Carolina"], ["ND","North Dakota"], ["OH","Ohio"],
["OK","Oklahoma"],
        ["OR","Oregon"], ["PA","Pennsylvania"], ["RI","Rhode Island"],
        ["SC","South Carolina"], ["SD","South Dakota"],
["TN","Tennessee"],
        ["TX","Texas"], ["UT","Utah"], ["VT","Vermont"],
["VA","Virginia"],
        ["WA","Washington"], ["WV","West Virginia"], ["WI","Wisconsin"],
        ["WY","Wyoming"]]
end

STATES = [
    [ "Alabama", "AL" ],
    [ "Alaska", "AK" ],
    [ "Arizona", "AZ" ],
    [ "Arkansas", "AR" ],
    [ "California", "CA" ],
    [ "Colorado", "CO" ],
    [ "Connecticut", "CT" ],
    [ "Delaware", "DE" ],
    [ "Florida", "FL" ],
    [ "Georgia", "GA" ],
    [ "Hawaii", "HI" ],
    [ "Idaho", "ID" ],
    [ "Illinois", "IL" ],
    [ "Indiana", "IN" ],
    [ "Iowa", "IA" ],
    [ "Kansas", "KS" ],
    [ "Kentucky", "KY" ],
    [ "Louisiana", "LA" ],
    [ "Maine", "ME" ],
    [ "Maryland", "MD" ],
    [ "Massachusetts", "MA" ],
    [ "Michigan", "MI" ],
    [ "Minnesota", "MN" ],
    [ "Mississippi", "MS" ],
    [ "Missouri", "MO" ],
    [ "Montana", "MT" ],
    [ "Nebraska", "NE" ],
    [ "Nevada", "NV" ],
    [ "New Hampshire", "NH" ],
    [ "New Jersey", "NJ" ],
    [ "New Mexico", "NM" ],
    [ "New York", "NY" ],
    [ "North Carolina", "NC" ],
    [ "North Dakota", "ND" ],
    [ "Ohio", "OH" ],
    [ "Oklahoma", "OK" ],
    [ "Oregon", "OR" ],
    [ "Pennsylvania", "PA" ],
    [ "Rhode Island", "RI" ],
    [ "South Carolina", "SC" ],
    [ "South Dakota", "SD" ],
    [ "Tennessee", "TN" ],
    [ "Texas", "TX" ],
    [ "Utah", "UT" ],
    [ "Vermont", "VT" ],
    [ "Virginia", "VA" ],
    [ "Washington", "WA" ],
    [ "West Virginia", "WV" ],
    [ "Wisconsin", "WI" ],
    [ "Wyoming", "WY" ]
  ].freeze

 STATES = [
    [ "", "" ],
    [ "Alabama", "Alabama" ],
    [ "Alaska", "Alaska" ],
    [ "Arizona", "Arizona" ],
    [ "Arkansas", "Arkansas" ],
    [ "California", "California" ],
    [ "Colorado", "Colorado" ],
    [ "Connecticut", "Connecticut" ],
    [ "Delaware", "Delaware" ],
    [ "Florida", "Florida" ],
    [ "Georgia", "Georgia" ],
    [ "Hawaii", "Hawaii" ],
    [ "Idaho", "Idaho" ],
    [ "Illinois", "Illinois" ],
    [ "Indiana", "Indiana" ],
    [ "Iowa", "Iowa" ],
    [ "Kansas", "Kansas" ],
    [ "Kentucky", "Kentucky" ],
    [ "Louisiana", "Louisiana" ],
    [ "Maine", "Maine" ],
    [ "Maryland", "Maryland" ],
    [ "Massachusetts", "Massachusetts" ],
    [ "Michigan", "Michigan" ],
    [ "Minnesota", "Minnesota" ],
    [ "Mississippi", "Mississippi" ],
    [ "Missouri", "Missouri" ],
    [ "Montana", "Montana" ],
    [ "Nebraska", "Nebraska" ],
    [ "Nevada", "Nevada" ],
    [ "New Hampshire", "New Hampshire" ],
    [ "New Jersey", "New Jersey" ],
    [ "New Mexico", "New Mexico" ],
    [ "New York", "New York" ],
    [ "North Carolina", "North Carolina" ],
    [ "North Dakota", "North Dakota" ],
    [ "Ohio", "Ohio" ],
    [ "Oklahoma", "Oklahoma" ],
    [ "Oregon", "Oregon" ],
    [ "Pennsylvania", "Pennsylvania" ],
    [ "Rhode Island", "Rhode Island" ],
    [ "South Carolina", "South Carolina" ],
    [ "South Dakota", "South Dakota" ],
    [ "Tennessee", "Tennessee" ],
    [ "Texas", "Texas" ],
    [ "Utah", "Utah" ],
    [ "Vermont", "Vermont" ],
    [ "Virginia", "Virginia" ],
    [ "Washington", "Washington" ],
    [ "West Virginia", "West Virginia" ],
    [ "Wisconsin", "Wisconsin" ],
    [ "Wyoming", "Wyoming" ]
  ]

发表在 Ruby on Rails | 留下评论

Ruby on Rails页面缓存

三种方式 Page Caching, Action Caching和 Fragment Caching

缓存默认只在production 环境下启动

Page Caching
caches_page :public_content
以URL为准
expire_page :action =>"public_content"

Action Caching
caches_action :premium_content
以URL为准
 expire_action :action => "premium_content", :id => article
 Page Caching 和 Action Caching的实例:
class ContentController < ApplicationController
 before_filter :verify_premium_user, :except => :public_content
 caches_page :public_content
 caches_action :premium_content
 cache_sweeper :article_sweeper,
        :only => [ :create_article,
        :update_article,
        :delete_article ]
 def public_content
  @articles = Article.list_public
 end
 def premium_content
  @articles = Article.list_premium
 end
 private
 def verify_premium_user
  return
   user = session[:user_id]
   user = User.find(user)
  if user
   unless user && user.active?
   redirect_to :controller =>  "login", :action => "signup_new"
  end
 end
end

删除过期缓存内容:
app/models中加article_sweeper.rb
class ArticleSweeper < ActionController::Caching::Sweeper
 observe Article
 def after_create(article)
  expire_public_page
 end
 def after_update(article)
  expire_article_page(article.id)
 end
 def after_destroy(article)
  expire_public_page
  expire_article_page(article.id)
 end
 private
 def expire_public_page
  expire_page(:controller => "content", :action => ‘public_content’)
 end
 def expire_article_page(article_id)
  expire_action(:controller =>  "content",
        :action => "premium_content",
        :id => article_id)
 end
end
app/public/content/show/1默认caches_page文件路径
app/public/content/show/1.html

Fragment Caching
controller:
class Blog1Controller < ApplicationController
 def list
  @dynamic_content = Time.now.to_s
  unless read_fragment(:action => ‘list’)
   logger.info("Creating fragment")
   @articles = Article.find_recent
  end
 end
end
#read_fragment()查看一个action的fragment缓存是否存在
view:
<%= @dynamic_content %> <!– 动态内容 –>
<% cache do %> <!– 缓存开始–>
 <ul>
 <% for article in @articles -%>
  <li><p><%= h(article.body) %></p></li>
 <% end -%>
 </ul>
<% end %> <!– 结束缓存 –>
<%= @dynamic_content %> <!– 其它动态内容 –>

使用多个缓存段:
<% cache(:action => ‘list’, :part => ‘articles’) do %>
 <ul>
 <% for article in @articles -%>
  <li><p><%= h(article.body) %></p></li>
 <% end -%>
 </ul>
<% end %>
<% cache(:action => ‘list’, :part => ‘counts’) do %>
 <p>There are a total of <%= @article_count %> articles.</p>
<% end %>
#使用:part参数区分同一action下的不同缓存段

缓存过期
controller:
class Blog2Controller < ApplicationController
 def list
  @dynamic_content = Time.now.to_s
  @articles = Article.find_recent
  @article_count = @articles.size
 end
 def edit
  # 编辑文章时不更新统计缓存
  expire_fragment(:action => ‘list’, :part => ‘articles’)
  redirect_to(:action => ‘list’)
 end
 def delete
  #删除文章时同时删除两个缓存
  expire_fragment(:action => ‘list’, :part => ‘articles’)
  expire_fragment(:action => ‘list’, :part => ‘counts’)
  redirect_to(:action => ‘list’)
 end
end

expire_fragment()可接正则表达式
expire_fragment(%r{/blog2/list. })

Fragment Caching存储选项设置:
ActionController::Base.fragment_cache_store = <下面的选项之一>
ActionController::Caching::Fragments::FileStore.new(path)
ActionController::Caching::Fragments::DRbStore.new(url)
ActionController::Caching::Fragments::MemCachedStore.new(host)

发表在 Ruby on Rails | 留下评论

Ruby on Rails Action Controller学习笔记

自动增加预载model方法:
class StoreController < ApplicationController
 model :cart, :line_item
 observer :stock_control_observer
 # …

如果没有找到相应的action, method_missing()将被调用
如果没有任何action, Rails会直接找template显示.

Ruby on Rails链接
Routing Requests
配置文件:config/routes.rb
ActionController::Routing::Routes.draw do |map|
 map.connect ‘:controller/service.wsdl’, :action => ‘wsdl’
 map.connect ‘:controller/:action/:id’
end

map.connect可用参数:
:defaults => { :name => "value", …}
 设默认值,默认为:defaults => { :action => "index", :id => nil }
:requirements => { :name =>/regexp/, …}
:name => value
:name => /regexp/

实例:
ActionController::Routing::Routes.draw do |map|
 #从上到下优先级降低.
 #’http://my.app/blog/&#39; 直接显示 index
 map.connect "blog/",
   :controller => "blog",
   :action =>"index"
 #按日期访问博客文章列表
 map.connect "blog/:year/:month/:day",
      :controller =>"blog",
      :action =>"show_date",
      :requirements => { :year => /(19|20)\d\d/,
               :month => /[01]?\d/,
               :day => /[0-3]?\d/},
      :day =>nil,
      :month =>nil
 # 按文章ID显示文章内容
 map.connect "blog/show/:id",
      :controller => "blog",
      :action =>"show",
      :id => /\d+/
 # 管理页面,常规
 map.connect "blog/:controller/:action/:id"
 # 其它
 map.connect "*anything",
      :controller =>"blog",
      :action =>"unknown_request"
 #=> URL>junk
 #=>@params = {:anything=>["junk"], :controller=>"blog", :action=>"unknown_request"}
end

链接生成url_for
@link = url_for :controller => "store", :action => "display", :id => 123
生成:http://pragprog.com/store/display/123
url_for(:controller => "store", :action => "list",
 :id => 123, :extra => "wibble")
生成:http://rubygarden.org/store/list/123?extra=wibble
url_for(:overwrite_params => {:year => "2002"})
生成:http://pragprog.com/blog/2002/4/15
#url_for会使用默认环境中的参数自动补充出完整的地址
#但一般补最后面的
#使用:overwrite_params使之补前面的.
url_for(:year=>year, :month=>sprintf("%02d", month), :day=>sprintf("%02d", day))
用来填充位数???
url_for(:controller => "/store", :action => "purchase", :id => 123)
#=> http://my.app/store/purchase/123
url_for(:controller => "/archive/book", :action => "record", :id => 123)
#=> http://my.app/archive/book/record/123

redirect_to(:action =>’delete’, :id => user.id)
# 和上面的一样:
redirect_to(:action => ‘delete’, :id => user)

default_url_options()
:anchor string #+string
:host string  (helper.pragprog.com:8080)
:only_path boolean
:protocol string ("https://";)
:trailing_slash boolean (+"/"?)

有名字的 Routes
map.date "blog/:year/:month/:day",
    :controller =>"blog",
    :action =>"show_date",
    :requirements => { :year => /(19|20)\d\d/,
            :month => /[01]?\d/,
            :day => /[0-3]?\d/},
    :day =>nil,
    :month =>nil
可调用
date_url(:year => 2003, :month => 2)
#=> http://pragprog.com/blog/2003/2

方法
把action藏起来,让它使用URL访问不了.
hide_action :check_credit
def check_credit(order)
# …
end

Controller Environment
request
  domain()
  remote_ip()
  env() 如:request.env['HTTP_ACCEPT_LANGUAGE']
  method (:delete, :get, :head,:post, or :put.)
   delete?, get?, head?, post?, and put?
class BlogController < ApplicationController
 def add_user
  if request.get?
   @user = User.new
  else
   @user = User.new(params[:user])
   @user.created_from_ip = request.env["REMOTE_HOST"]
   if @user.save
    redirect_to_index("User #{@user.name} created")
   end
  end
 end
end

params
cookies
response
session
headers

runder()
更改默认template目录
ActionController::Base.template_root=dir_path
render(:text=>string)
class HappyController < ApplicationController
 def index
  render(:text =>"Hello there!")
 end
end

render(:inline=>string, [ :type =>"rhtml"|"rxml"] )
class SomeController < ApplicationController
 if RAILS_ENV == "development"
  def method_missing(name, *args)
   render(:inline => %{  
    <h2>Unknown action:#{name}</h2>
    Here are the request parameters:<br/>
    <%= debug(params) %> })
  end
 end
end

render(:action =>action_name)
def display_cart
 if @cart.empty?
  render(:action => :index)
 else
  # …
 end
end

render(:file =>path, [ :use_full_path =>true|false] )

render(:template =>name)
class BlogController < ApplicationController
 def index
  render(:template =>"blog/short_list")
 end
end

render(:partial =>name, …)
render(:nothing => true)
render_to_string() 不发送,直接转为string

发送
send_data
def sales_graph
png_data = Sales.plot_for(Date.today.month)
 send_data(png_data, :type => "image/png", :disposition => "inline")
end

send_file
def send_secret_file
 send_file("/files/secret_list")
 headers["Content-Description"] = "Top secret"
end

有些地方使用redirect_to代替render
redirect_to(:action => ‘display’)

redirect_to(options…)
redirect_to(path)
redirect_to(url)

Cookies and Sessions
Cookies只能存String
class CookiesController < ApplicationController
 def action_one
  cookies[:the_time] = Time.now.to_s
  redirect_to :action =>"action_two"
 end
 def action_two
  cookie_value = cookies[:the_time]
  render(:text => "The cookie says it is #{cookie_value}")
 end
end

cookies[:marsupial] = { :value => "wombat",
          :expires => 30.days.from_now,
          :path =>"/store" }
可用选项 :domain, :expires,:path, :secure, and :value

Sessions
保存model时要先预载:
class BlogController < ApplicationController
 model :user_preferences

设置session:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] = ‘my_app’
可用选项:
:database_manager
:session_domain
:session_id
:session_key
:session_path
:session_secure
Session保存选择:
:database_manager => CGI::Session::PStore
  flat file (单服务器推荐)
:database_manager => CGI::Session::ActiveRecordStore
:database_manager => CGI::Session::DRbStore
:database_manager => CGI::Session::MemCacheStore

Flash用于在两个action传输暂时信息
flash.now用法实例:
class BlogController
 def display
  unless flash[:note]
   flash.now[:note] = "Welcome to my blog"
  end
  @article = Article.find(params[:id])
 end
end

flash.keep用法实例:
class SillyController
 def one
  flash[:note] = "Hello"
  redirect_to :action => "two"
 end
 def two
  flash.keep(:note)
  redirect_to :action => "three"
 end
 def three
  # flash[:note] => "Hello"
 render
 end
end

Filters
class BlogController < ApplicationController
 before_filter :authorize, :only => [ :delete, :edit_comment ]
 after_filter :log_access, :except => :rss
 # …
before_filter可用来替换全局页面中的字符,如{$title}
也可用来给页面 Zlib压缩
Around Filters可用来计算action用时

Verification
class BlogController < ApplicationController
 verify :only => :post_comment,
 :session => :user_id,
 :add_flash => { :note =>"You must log in to comment"},
 :redirect_to => :index
 # …
使用范围:
:only =>:name or [ :name, ... ]
:except =>:name or [ :name, ... ]
通过条件:
:flash =>:key or [ :key,... ]
:method =>:symbol or [ :symbol, ... ](:get, :post, :head, or :delete)
:params =>:key or [ :key,... ]
:session =>:key or [ :key,... ]
反应:
:add_flash =>hash
:redirect_to =>params

 GET Requests
 GET用来获取信息
 POST用来传输更改数据库的信息
 <%= link_to ‘删除评论’, { :action => ‘com_destroy’, :id => comment },
     :confirm =>"你确定要删除这则评论吗?",
     :post => true %>
使用forms和buttons

发表在 Ruby on Rails | 留下评论

更多Ruby on Rails的Active Record

Callbacks
class User < ActiveRecord::Base
 before_destroy :dont_destroy_dave
 def dont_destroy_dave
  raise "Can’t destroy dave" if name == ‘dave’
 end
end

class Order < ActiveRecord::Base
 # ..
 def before_save
  self.payment_due ||= Time.now + 30.days
 end
end

class Order < ActiveRecord::Base
 before_validation :normalize_credit_card_number
 after_create do |order|
  logger.info "Order #{order.id} created"
 end
 protected
 def normalize_credit_card_number
  self.cc_number.gsub!(/-\w/, ”)
 end
end

Callback Objects 全局可以访问
class CreditCardCallbacks
 # Normalize the credit card number
 def before_validation(model)
  model.cc_number.gsub!(/-\w/,”)
 end
end

class Order < ActiveRecord::Base
 before_validation CreditCardCallbacks.new
 # …
end
 Subscription < ActiveRecord::Base
class
 before_validation CreditCardCallbacks.new
 # …
end
可用于数据加密

格式化数据类型:
class LineItem < ActiveRecord::Base
 def total_price
  Float(read_attribute("total_price"))
 end
end

数量单位转换:
class ProductData < ActiveRecord::Base
 CUBITS_TO_INCHES = 18
 def length
  read_attribute("length") * CUBITS_TO_INCHES
 end
 
 def length=(inches)
  write_attribute("length", Float(inches) / CUBITS_TO_INCHES)
 end
end

find_by_sql没有读取PK时不能保存的实例:
result = LineItem.find_by_sql("select quantity from line_items")
result.each do |li|
 li.quantity += 2
 li.save
end

有特殊功能的段名
created_at, created_on, updated_at, updated_on
 ror自动更新的时间段
 修改ActiveRecord::Base.default_timezone = :utc参数更改变时区
lock_version
type
 (employee, manager, person..)
id
XXX_id (FK)
xxx_count
position (acts_as_list)
partent_id (acts_as_tree)

发表在 Ruby on Rails | 留下评论

Ruby on Rails 的检验方法(Validation Helpers)大全

可以自定义validate(), 这个方法在每次保存数据时都会被调用.
如:
def validate
 if name.blank? && email.blank?
  errors.add_to_base("You must specify a name or an email address")
 end
end
同时也可以自定义 validate_on_create(), validate_on_update()方法.
 valid?()方法可以随时调用,用来测试数据是否能通过校验
返回的错误信息可用 error_messages_for(model)方法显示.
如:<%= error_messages_for ‘article’ %>

校验大全:
validates_acceptance_of
 指定checkbox应该选中. (如:(*)我同意条款)
 用法:validates_acceptance_of attr… [ options... ]
 参数:message text  默认:“must be accepted.”
   :on :save, :create, or :update
 实例:
 class Order < ActiveRecord::Base
  validates_acceptance_of :terms,
              :message => "Please accept the terms to proceed"
 end

validates_associated
 查验指定的object.
 用法:validates_associated name… [ options... ]
 参数:message text 默认: is “is invalid.”
   :on :save, :create, or :update
 实例:
 class Order < ActiveRecord::Base
  has_many :line_items
  belongs_to :user
  validates_associated :line_items,
            :message => "are messed up"
  validates_associated :user
 end

validates_confirmation_of
 数据重校
 用法:validates_confirmation_of attr… [ options... ]
 参数:message text 默认 “doesn’t match confirmation.”
   :on :save, :create, or :update
 实例:
 对密码表:
 <%= password_field "user", "password" %><br />
 <%= password_field "user", "password_confirmation" %><br />
 #第二表名为xxxx_confirmation
 class User < ActiveRecord::Base
  validates_confirmation_of :password
 end

validates_each
 使用block检验一个或一个以上参数.
 用法:validates_each attr… [ options... ] { |model, attr, value| … }
 参数:allow_nil boolean 设为true时跳过nil对象.
   :on :save, :create, or :update
 实例:
 class User < ActiveRecord::Base
  validates_each :name, :email do |model, attr, value|
   if value =~ /groucho|harpo|chico/i
    model.errors.add(attr,"You can’t be serious, #{value}")
   end
  end
 end

validates_exclusion_of
 确定被检对象不包括指定数据
 用法:validates_exclusion_of attr…, :in => enum [ options... ]
 #enum指一切可用include?()判断的范围.
 参数:allow_nil 设为true将直接跳过nil对象.
   :in (or :within) enumerable
   :message text 默认为: “is not included in the list.”
   :on :save, :create, or :update
 实例:
 class User < ActiveRecord::Base
  validates_exclusion_of :genre,
            :in => %w{ polka twostep foxtrot },
            :message =>"no wild music allowed"
  validates_exclusion_of :age,
             :in => 13..19,
             :message =>"cannot be a teenager"
 end

validates_inclusion_of
 确认对象包括在指定范围
 用法:validates_inclusion_of attr…, :in => enum [ options... ]
 参数:allow_nil 设为true直接跳过nil对象
   :in (or :within) enumerable An enumerable object.
   :message text 默认:“is not included in the list.”
   :on :save, :create, or :update
 实例:
 class User < ActiveRecord::Base
  validates_inclusion_of :gender,
            :in => %w{ male female },
            :message =>"should be ‘male’ or ‘female’"
  validates_inclusion_of :age,
            :in => 0..130,
            :message =>"should be between 0 and 130"
 end

validates_format_of
 用正则检验对象
 用法:validates_format_of attr…, :with => regexp [ options... ]
 参数:message text 默认为: “is invalid.”
   :on :save, :create, or :update
   :with 正则表达式
 实例:
 class User < ActiveRecord::Base
  validates_format_of :length, :with => /^\d+(in|cm)/
 end

validates_length_of
 检查对象长度
 用法:validates_length_of attr…, [ options... ]
 参数:in (or :within) range
   :is integer
   :minimum integer
   :maximum integer
   :message text 默认文字会根据参数变动,可使用%d 取代确定的最大,最小或指定数据.
   :on :save, :create, or :update
   :too_long text 当使用了 :maximum后的 :message
   :too_short text ( :minimum )
   :wrong_length ( :is)
 实例:
 class User < ActiveRecord::Base
  validates_length_of :name, :maximum => 50
  validates_length_of :password, :in => 6..20
  validates_length_of :address, :minimum => 10,
                :message =>"seems too short"
 end

validates_numericality_of
 检验对象是否为数值
 用法:validates_numericality_of attr… [ options... ]
 参数:message text 默认 “is not a number.”
   :on :save, :create, or :update
   :only_integer
 实例:
 class User < ActiveRecord::Base
  validates_numericality_of :height_in_meters
  validates_numericality_of :age, :only_integer => true
 end

validates_presence_of
 检验对象是否为空
 用法:validates_presence_of attr… [ options... ]
 参数:message text 默认:“can’t be empty.”
   :on :save, :create, or :update
 实例:
 class User < ActiveRecord::Base
  validates_presence_of :name, :address
 end

validates_uniqueness_of
 检验对象是否不重复
 用法:validates_uniqueness_of attr… [ options... ]
 参数:message text 默认: “has already been taken.”
   :on :save, :create, or :update
   :scope attr 指定范围
 实例:
 class User < ActiveRecord::Base
  validates_uniqueness_of :name
 end

 class User < ActiveRecord::Base
  validates_uniqueness_of :name, :scope =>"group_id"
 end
 #指定在同一group_id的条件下不重复.

常用正则:

E-Mail地址格式:
validates_format_of     :email,
                        :with       => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
                        :message    => ‘email must be valid’

网址格式:
validates_uri_existence_of :url, :with =>
        /(^$)|(^(http|https)://[a-z0-9] ([-.]{1}[a-z0-9] )*.[a-z]{2,5}(([0-9]{1,5})?/.*)?$)/ix

 

发表在 Ruby on Rails | 留下评论

Ruby on Rails 的Active Record之Acts As List和Acts As Tree

Acts As List实例:
在子表中加parent_idposition

定义:
class Parent < ActiveRecord::Base
 has_many :children, :order => :position
end
class

Child < ActiveRecord::Base
 belongs_to :parent
 acts_as_list :scope => :parent_id
#:scope 指定在parent_id相同范围内.
end

向表中添加数据:
parent = Parent.new
%w{ One Two Three Four}.each do |name|
 parent.children.create(:name => name)
end
parent.save

定义显示方法:
def display_children(parent)
 puts parent.children.map {|child| child.name }.join(", ")
end

调用实例:
display_children(parent) #=> One, Two, Three, Four

puts parent.children[0].first? #=> true
#使用last?(), first?()判断行位置

two = parent.children[1]
puts two.lower_item.name  #=> Three
puts two.higher_item.name #=> One
#使用.lower_item访问下一行数据, 使用.higher_item访问上一行数据,使用

parent.children[0].move_lower
parent.reload

display_children(parent) #=> Two, One, Three, Four
#使用mover_lower(), mover_higher()可移动行数据
#使用parent.reload刷新数据

parent.children[2].move_to_top
parent.reload
display_children(parent) #=> Three, Two, One, Four
#使用move_to_top(), move_to_bottom()移动行数据

parent.children[2].destroy
parent.reload
display_children(parent) #=> Three, Two, Four
#一行数据删除后其下面的行会自动跟上

Acts As Tree实例:
向子表新增parent_id (int), 并将设定为表内关联键

定义方法:
class Category < ActiveRecord::Base
 acts_as_tree :order =>"name"
end

向表格添加数据:
root = Category.create(:name => "Books")
fiction = root.children.create(:name =>"Fiction")
non_fiction = root.children.create(:name => "Non Fiction")

non_fiction.children.create(:name =>"Computers")
non_fiction.children.create(:name =>"Science")
non_fiction.children.create(:name =>"Art History")

fiction.children.create(:name =>"Mystery")
fiction.children.create(:name => "Romance")
fiction.children.create(:name =>"Science Fiction")

定义显示方法:
def display_children(parent)
 puts parent.children.map {|child| child.name }.join(", ")
end

调用实例:
display_children(root) # Fiction, Non Fiction

sub_category = root.children.first
puts sub_category.children.size #=> 3
display_children(sub_category) #=> Mystery, Romance, Science Fiction

non_fiction = root.children.find(:first, :conditions => "name = ‘Non Fiction’")

display_children(non_fiction) #=> Art History, Computers, Science

puts non_fiction.parent.name #=> Books

:counter_cache => true+children_count段也可以在这里使用.用来自动计算子表行数.

发表在 Ruby on Rails | 一条评论

Ruby on Rails数据表格关系

一对一关系实例: one-to-one
class Order < ActiveRecord::Base
has_one :paid_order,
    :class_name =>"Order",
    :foreign_key => "order_id",
    :conditions => "paid_on is not null"
在表格上加order_id (表格名单数_id)
class Invoice < ActiveRecord::Base
belongs_to :order

可选参数:class_name, :foreign_key,  :order, :conditions
:dependent => true #删除主表行时同时删除子行
自定义的order用法:
class Customer < ActiveRecord::Base
has_many :orders
has_one :most_recent_order,
    :class_name => ‘Order’,
    :order => ‘created_at DESC’
end

主.从 将被保存
an_invoice = Invoice.new(…)
order.invoice = an_invoice # invoice被保存
从.主 将要手动保存

新增加的方法:
product(force_reload=false)
product=(obj)
build_product(attributes={})
create_product(attributes={})

一对多关系(one-to-many)
class Order < ActiveRecord::Base
has_many :line_items
可选参数除了上面的,还有:exclusively_dependent, :finder_sql,:counter_sql
:exclusively_dependent 在子行没有其它表格瓜葛的情况下使用, 加快处理速度.
:finder_sql的使用实例:
class Order < ActiveRecord::Base
has_many :rails_line_items,
     :class_name => "LineItem",
     :finder_sql => "select l. * from line_items l, products p " +
     " where l.product_id = p.id " +
     " and p.title like ‘%rails%’"
end
order的用法:
class Order < ActiveRecord::Base
has_many :line_items,
   :order =>"quantity, unit_price DESC"
end

主.从 将被保存
an_invoice = Invoice.new(…)
order.invoices <<an_invoice # invoice

class LineItem < ActiveRecord::Base
belongs_to :order
. . .

has_many后可以引用集合:
order = Order.find(123)
total = 0.0
order.line_items.each do |li|
 total += li.quantity * li.unit_price
end

新增加的方法:
orders(force_reload=false)
orders <<order
orders.push(order1, …)
orders.delete(order1, …)
orders.clear
orders.find(options…)
orders.build(attributes={})
orders.create(attributes={})

多对多关系(many-to-many):
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
. . .
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
. . .

要创建一个中间表格:
categories_products
两表格名字复数形式相联, 排字母前后排序

表格内连关联键

预载子表
用:include将子表内容加入内存,提高查询速度, 但损耗内存:
for post in Post.find(:all, :include => [:author, :comments])
 puts "Post: #{post.title}"
 puts "Written by: #{post.author.name}"
 puts "Last comment on: #{post.comments.first.created_on}"
end

自动计算子表行数
 belongs_to加参数:counter_cache => true
 数据库加 子表格名(复数)_count 段, 并加 :default=>0参数.
 然后用 .size可以读取子表行数.
刷新数据读法:product.line_items(:refresh).size

发表在 Ruby on Rails | 2 条评论

Ruby on Rails 数据库Migration操作语句实例

def self.up     # db schema更新到下一版本
  create_table :table, :force => true do |t| #创建表格
    t.column :name, :string
    t.column :age, :integer, { :default => 42 }
    t.column :description, :text
    # :string, :text, :integer, :float, :datetime, :timestamp, :time, :date,
    # :binary, :boolean
  end
  add_column :table, :column, :type #添加段

  rename_column :table, :old_name, :new_name #修改段名
  change_column :table, :column, :new_type #修改段数据类型
  execute "SQL语句"
  add_index :table, :column, :unique => true, :name => ‘some_name’  #添加索引
  add_index :table, [ :column1, :column2 ]
end

def self.down   # 撤消操作
  rename_column :table, :new_name, :old_name
  remove_column :table, :column
  drop_table :table #删除表格
  remove_index :table, :column
end

发表在 Ruby on Rails | 留下评论

Ruby on Rails HTML表单语句大全

表单开始标签:
<%= form_tag { :action => :save }, { :method => :post } %>
Use :multipart => true to define a Mime-Multipart form (for file uploads)
表单结束标签:
<%= end_form_tag %>

文本框 Text fields
<%= text_field :modelname, :attribute_name, options  %>
生成:
<input type="text" name="modelname[attribute_name]" id="attributename" />

实例:

text_field "post", "title", "size" => 20
    <input  type="text" id="post_title" name="post[title]"
            size="20" value="#{@post.title}" />

隐藏框:
<%= hidden_field … %>

密码框:
<%= password_field … %>

文件框
<%= file_field … %>

Rails Textarea框
<%= text_area … %>
实例:
text_area "post", "body", "cols" => 20, "rows" => 40
    <textarea cols="20" rows="40" id="post_body" name="post[body]">
        #{@post.body}
    </textarea>

单选框 Radio Buttons
<%= radio_button :modelname, :attribute, :tag_value, options %>
实例:
radio_button "post", "category", "rails"
radio_button "post", "category", "java"
    <input type="radio" id="post_category" name="post[category]" value="rails"
           checked="checked" />
    <input type="radio" id="post_category" name="post[category]" value="java" />

多选框 Check Box
<%= check_box :modelname, :attribute, options, on_value, off_value %>
实例
check_box "post", "validated"   # post.validated? returns 1 or 0
    <input type="checkbox" id="post_validate" name="post[validated]"
           value="1" checked="checked" />
    <input name="post[validated]" type="hidden" value="0" />

check_box "puppy", "gooddog", {}, "yes", "no"
    <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
    <input name="puppy[gooddog]" type="hidden" value="no" />

<%= select :variable, :attribute, choices, options, html_options %>

下拉菜单框 Select Menu
select  "post",        
        "person_id",   
        Person.find_all.collect {|p| [ p.name, p.id ] },
        { :include_blank => true }

 <select name="post[person_id]">
   <option></option>
   <option value="1" selected="selected">David</option>
   <option value="2">Sam</option>
   <option value="3">Tobias</option>
 </select>

Collection Selection
<%= collection_select :variable, :attribute, choices, :id, :value %>

日期选择框:
<%= date_select :variable, :attribute, options %>
<%= datetime_select :variable, :attribute, options %>
实例:
date_select "post", "written_on"
date_select "user", "birthday", :start_year => 1910
date_select "user", "cc_date", :start_year => 2005,
                               :use_month_numbers => true,
                               :discard_day => true,
                               :order => [:year, :month]

datetime_select "post", "written_on"

发表在 Ruby on Rails | 留下评论

Ruby on Rails数据库操作

数据库元被影射成对象
(object-relational mapping (ORM)层)
table<=>class
row<=>object
column<=>object attribute

class和table的命名对应关系实例
Order<=>orders
TaxAgency<=>tax_agencies
Person<=>people

复数形式关闭方法config/environment.rb:
ActiveRecord::Base.pluralize_table_names = false
自定义表格名称方法:
class Sheep < ActiveRecord::Base
 set_table_name "sheep"
end

Ruyb数据类型和SQL数据类型对应关系表
int,integer<=>Fixnum
float,double,decimal,numeric<=>Float
interval,date<=>Date
datetime,time<=>Time
char,varchar,string,clob,blob,text<=>String
boolean<=>see text…

访问属性(数据库列):
account[:balance] #=> 返回当前值
account[:balance] = 0.0 #=> 指定数值

修正数据库列的取值范围的方法:
class Account < ActiveRecord::Base
 def balance=(value)
  raise BalanceTooLow if value < MINIMUM_LEVEL
  self[:balance] = value
 end
end

访问属性(数据库列)更方便的方法:
account.balance #=> 返回当前值
account.balance = 0.0 #=> 指定数值

以上方式得到的数据库数据将是ruby按自身的数据类型格式化好的,如果要得到原始数据,可用以下形式代码:
account.balance_before_type_cast #=> "123.4", 字符串
account.release_date_before_type_cast #=> "20050301"

是非属性
在ruby中只有falsenil才被判断为false

数据库主键(Primary Keys)
Ruby on Rails默认以id为主键

自定义主键的方法:
class BadBook < ActiveRecord::Base
 set_primary_key "isbn"
end

数据创建,读取,更新和删除(CRUD:Create, Read, Update, Delete)

创建新数据

实例:
an_order = Order.new
an_order.name ="Dave Thomas"
an_order.save #在save()之前所有数据只存在内存中

用以下方式可以减少产生一个an_order变量:
Order.new do |o|
 o.name = "Dave Thomas"
 # . . .
 o.save
end

当数据来自HTML表单时,可以考虑用以下方式:
an_order = Order.new(
 :name =>"Dave Thomas",
#…
)
an_order.save

使用create()代换new()可直接保存到数据库,省去an_order.save:
an_order = Order.create(
 :name => "Dave Thomas")

可以使用hash同时保存多组数据:
 orders = Order.create(
  [ { :name =>"Dave Thomas" },
   { :name =>"Andy Hunt" } ] )

new()或create()也可以直接接参数:
order = Order.create(params)

读取数据
an_order = Order.find(27)
# 直接找出id = 27的数据,可以同时读取多个object.
an_order = Order.find_by_id(27)
# 效果类似,但一次只能读一个,在找不到符合的object时返回nil,而不是错误。
# 从一个表单读取product id列表,然后计算这些商品的总价:
product_list = params[:product_ids]
total = 0.0
Product.find(product_list).each {|prd| total += prd.total}

带条件的读取:
pos = Order.find(:all,
:conditions => "name = ‘dave’ and pay_type = ‘po’")

不安全的表单参数传递读取数据库:
name = params[:name]
# 此方法有被SQL注入方式入侵的风险!!!
pos = Order.find(:all,
:conditions =>"name = ‘#{name}‘ and pay_type = ‘po’")
#注意上面单双引号的使用及变量的传递方法

更安全的方法:
name = params[:name]
pos = Order.find(:all,
:conditions => ["name = ? and pay_type = 'po'", name])

你也可以这样:
name = params[:name]
pay_type = params[:pay_type]
pos = Order.find(:all,
:conditions => ["name = :name and pay_type = :pay_type",
{:pay_type => pay_type, :name => name}])

终极简化版:
pos = Order.find(:all,
:conditions => ["name = :name and pay_type = :pay_type", params])

排序和查找第3(?)至13(?)列的方法:
orders = Order.find(:all,
 :conditions =>"name = ‘Dave’",
 :order =>"pay_type, shipped_at DESC",
 :limit => 10
 :offset => 2)

联合数据表的查找方法(一般用不上):
LineItem.find(:all,
:conditions => "pr.title = ‘Programming Ruby’",
:joins =>"as li inner join products as pr on li.product_id = pr.id")

查找有序一列的方法:
order = Order.find( :first,
 :conditions =>"name = ‘Dave Thomas’",
 :order => "id DESC")

直接使用sql语句的查询方法:
items = LineItem.find_by_sql("select *, quantity*unit_price as total_price,products.title as title from line_items, products where line_items.product_id = products.id ")
li = items[0]
puts "#{li.title}: #{li.quantity}x#{li.unit_price} => #{li.total_price}"
你可以使用"as".

在这里你也可以传递参数:
Order.find_by_sql(["select * from orders where amount > ?",
params[:amount]])

计算行数
c1 = Order.count
c2 = Order.count(["name = ?", "Dave Thomas"])
c3 = LineItem.count_by_sql("select count(*) from line_items, orders  where line_items.order_id = orders.id and orders.name = ‘Dave Thomas’ ")
puts "Dave在#{c2}个定单里一共定了#{c3} 件商品 (目前定单总数:#{c1})"

动态查询
order = Order.find_by_name("Dave Thomas")#只查一列
orders = Order.find_all_by_name("Dave Thomas")
order = Order.find_all_by_email(params['email'])

可同时查多个条件,如:
user = User.find_by_name_and_password(name, pw)

重载数据库
stock = Market.find_by_ticker("RUBY")
loop do
 puts "Price = #{stock.price}"
 sleep 60
 stock.reload
end

更新数据
使用save()
order = Order.find(123)
order.name = "Fred"
order.save

orders = Order.find_by_sql("select id, name, pay_type from orders where id=123")
first = orders[0]
first.name ="Wilma"
first.save

使用update_attribute()
order = Order.find(123)
order.update_attribute(:name,"Barney")
order = Order.find(321)
order.update_attributes(:name => "Barney",
:email =>"barney@bedrock.com")

使用更快捷的update()
order = Order.update(12, :name => "Barney", :email => "barney@bedrock.com")

使用update_all()
result = Product.update_all("price = 1.1*price", "title like ‘%Java%‘")

save()和save!()
save()失败时返回nil
if order.save
 # 成功
else
 # 保存失败则…
end

save!()失败时出错
begin
 order.save!
rescue RecordInvalid => error
 # 保存失败RecordInvalid exception
end

数据锁(防止数据保存撞车)
加段:lock_version int default 0,

删除数据
delete()删除
Order.delete(123)
User.delete([2,3,4,5])
Product.delete_all(["price > ?", @expensive_price])

destroy()冻结(在model层面)
order = Order.find_by_name("Dave")
order.destroy
# … order将被冻结

数据库关系(相关键)参看:Ruby on Rails数据表格关系

发表在 Ruby on Rails | 留下评论