- 浏览: 25863 次
- 性别:
文章分类
最新评论
rails是作为ruby的gem进行安装的,需要注意安装相关的依赖包
对于ODBC的连接SQL数据库,需要进行不少的设置,包括控制面板内的管理工具,设置本地的dsn设置
创建rails应用后,可以通过rake db:migrate检查是否配置完成,也可以使用idea来执行判断
数据库database.yml配置如下
development:
adapter: sqlserver
mode: odbc
dsn: CHENHENG
username : sa
password : 123
其他大体如上
controllers 目录下可以创建对应的c部分,里面创建的文件命名格式为
admin_controller.rb
访问时URL主体部分为admin/action,
其中action为方法名,可以通过直接定义def action来访问自定义的方法
方法执行完,会自动跳转views/admin/目录下的对应action.html.erb类似规则的文件
使用rails建立model时,会自动在db/migrate目录下创建rb文件,可以创建数据库所需的表信息
动态网页内容.两种方式
一:erb,
使用<%=...%>执行ruby,输出变量,与Jsp标签类似
使用<%%>执行ruby语句,循环等,注意end的使用 注意其中<% ...-%>格式的使用,似乎用于去除
所产生的空格
如果需要在<%=%>中输出带特殊字符的ruby代码,可以使用
<%= h("Ann & Bill <frazers@isp.email>" ) %>中的h()
获取action中定义的局部变量的方式@var...
在action中定义的@var变量,可以直接在erb文件中使用<%= @var %>读取
创建超链接的方式, //指向其他的URL,将会忽视对相对和绝对路径的URL处理
修改rails数据库环境的方式,切换development等..
rake db:create RAILS_ENV='development'
在使用Idea开发时,需要注意使用scaffold生成脚手架时,参数格式如下
product title:string desc:text
product为model的名称,即数据库中表的名称映射,一般会被映射成复数s的形式
title为列名,string为orm的类型
完整的指令应该为generate scaffold -f product title:string desc:text image_url:string
在开发时,注意不要存在多个不同版本的gem,idea会默认使用最高版本的gem,忽视原有的配置,
可以使用gem uninstall 进行卸载,包括所依赖的相关版本
为已存在的model添加属性,主要目的是为数据库添加列,并且增加所需的记录
generate migration -f add_price_to_product price:decimal
将会生成新的migrate文件,用于记录新增的记录,同时也提供了还原的方式
然后运行rake db:migrate 执行语句即可,如果要在对应的html中进行显示,可以使用
generate scaffold -f product title:string desc:text image_url:string
再次执行生成
添加验证,
在model中添加验证的方式
validates_presence_of :title, :description, :image_url //验证指定的字段非空
validates_numericality_of :price //验证字段必须为数字
添加自定义验证的方式
validate :price_must_be_at_least_a_cent
protected
def price_must_be_at_least_a_cent
errors.add(:price, 'should be at least 0.01' ) if price.nil? ||price < 0.01 //这里主要是errors的使用
end
通过正则进行定义验证的方式
validates_format_of :image_url,
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG or PNG image.'
通过数据库进行验证
validates_uniqueness_of :title
可以通过建立controller时,可以使用带参数,同时创建action,并且会自动生成对应的erb页面
<%=h ... %> 用于转换内容中的HTML代码
格式化价格
<%= sprintf("$%0.02f" , product.price) %>
货币格式转换的方式
<%= number_to_currency(product.price) %>
rails提供了两种用于超链接的标签
button_to 用于生成一个form,并且使用post的提交方法
link_to 用于生成一个简单的a href,使用get方式
创建基于rails本身的session解决数据存储方案
rake db:sessions:create //保存在数据库中
然后执行rake db:migrate ,创建所需的表
在rails2.3中,需要在config/initializers/session_store.rb中配置
Action_controller.session_store = :active_record_store
存储在数据库中,主要用于提供了一种跨多机器的存储环境
建立专属的controller
application_controller.rb //注意是必须的重写,内容可以参考框架下的实现,可以直接拷贝
从http请求中获取参数
params[:key]
Flash域,用于保存临时显示的数据,原理与struts2类似,同样保存在session中,自动删除
常用于保存错误信息
记录错误信息与flash的使用
logger.error("Attempt to access invalid product #{params[:id]}" )
flash[:notice] = "Invalid product"
redirect_to :action => 'index" //URL跳转,重定向,可以通过重构抽取相同的内容到方法中
读取flash的时候,加入if判断是否存在会更好一些
<% if flash[:notice] -%>
<div id="notice"><%= flash[:notice] %></div>
<% end -%>
判断指定域中对象是否为空的方式
if session[:counter].nil? ,也可以采取||=进行缩写
在页面中使用标签导入其他erb内容,类似jsp的include
<%= render(:partial => "cart_item" , :collection => @cart.items) %>
同时在目标中,可以直接包含循环体内容,而不需要重新循环读取
直接集合了c:foreach和include
其中partial为var ,collection为items. 不过功能应该更丰富一些
其中特殊的一点是,只要将需要嵌入的文件命名为_cart_item.html.erb即可自动寻找到,与partial属性相关
:object => @cart 用于传入一个对象
生成一个Ajax请求的标签
<% form_remote_tag :url => { :action => 'add_to_cart', :id => product } do %>
<%= submit_tag "Add to Cart" %>
<% end %>
rjs文件,用于生成所需的js模板文件,使用上与erb类似
在layout文件中,加入以下标签,用于导入默认所需的js文件
<%= javascript_include_tag :defaults %>
在rjs模板中同样适用标签进行声明
page.replace_html("cart" , :partial => "cart" ,bject => @cart)
表示替换调用页面中id=cart元素中的html内容
使用内置的effects.js 特效 其中:current_item 为html中元素的id
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
上述代码同样定义在rjs文件中
helpers/ 目录中保存了与controller同名的module文件,用于为对应的controller提供更多功能
将会被自动include,不需要手动编写
在进行渲染时,可以通过判断选择不同的方式
respond_to do |format|
format.js if request.xhr?
format.html {redirect_to_index}
end
在rails建立一对多的主外键关联
在module中添加
一方:has_many :line_items 后者为其他model
多方:belongs_torder 后者同上
application_controller 作用类似web.xml,用于用代码代替配置工程中的属性
before_filter :authorize, :except => :login 配置过滤器
其中的anthorize
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin' , :action => 'login'
end
end
:except 用于设置例外的界面或请求
创建基于xml的渲染器,类似erb,rjs
respond_to do |format|
format.html //会根据http header中Accept:内容的不同,自动选择不同的请求render
format.xml { render :layout => false } //false用于关闭使用layout模板
end
扩展名如下,使用时候比较特殊一些
who_bought.xml.builder
xml.order_list(:for_product => @product.title) do
for o in @orders
xml.order do
xml.name(o.name)
xml.email(o.email)
end
end
end
其他情况下,根据路由routes.rb的配置,可以直接使用扩展名,返回不同的渲染
map.connect ':controller/:action/:id.:format
使用内置自动生成xml文件
format.xml { render :layout => false ,:xml => @product.to_xml(:include =>rders) }
调用model的to_xml方法
生成指定格式的feed xml格式文件
format.atom { render :layout => false }
生成JSON 的格式,针对http header请求
format.json { render :layout => false ,:json => @product.to_json(:include =>rders) }
生成文档
rake doc:app
i18n/test跳过,不研究
rails项目的目录结构
doc/ 用于存放项目的说明文档
lib/ 可以用于放置一些rb类,可以被controller,view,model中引入,注意需要加上目录
lib/tasks, 用用于放置自定义的take任务
log/用于放置日志信息
public/放置一些静态文件,css,js等,以及404等错误html页面
script/开发用的脚本
vendor/存放第三方插件,代码,用于采用非全局的gem等,
使用项目gem rake rails:freeze:gems
使用系统gem rake rails:unfreeze
其他rake rails:freeze:edge
config / 目录 , 用于存放一些配置文件,数据库,环境等
ruby script/server -e development //切换运行环境,参数还包括test,production
config/database.yml 数据库连接的配置
Active Support
主要为model中的类,rails为其扩展了许多方便的方法
对于集合的操作,继承了Enumerable中的方法
groups = posts.group_by {|post| post.author_id}
state_lookup = us_states.index_by {|state| state.short_name}
total_orders = Order.find(:all).sum {|order| order.value }
rails也对Array进行了扩展
puts [ "ant" , "bat" , "cat" ].to_sentence #=> "ant, bat, and cat"
对String的扩展也很多...除了字符的截取,还提供了一些英文 单数,复数的转换,大小写格式化
扩展自己的语法转换规则
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular "goose" , "geese"
end
对数字同样也提供了扩展
提供了字节,时间的便捷操作
时间和日期的扩展
date = Date.today
puts date.tomorrow
以及更多的日期格式化获取
对Ruby语法的扩展,如方法调用
groups = posts.group_by {|post| post.author_id}
转化成
groups = posts.group_by(&:author_id) , 节约了临时对象的编写
Migrations
Rails中使用对Migration的维护,来对数据库进行DDL操作,同时对每次的处理,都使用单独的文件进行
保存,便于版本的控制,其中也会将当前项目的db信息保存在表schema_migrations table中
最常见的执行 rake db:migrate,将会比对当前数据库表中与文件的区别,进行执行
对db版本的控制
rake db:migrate VERSION=20080601000010 //将版本调整至指定版本,
rake db:migrate:redo STEP=3 //效果一致
常见的列类型,使用在Migration文件中的add_column:属性中
:binary, :boolean, :date, :datetime, :decimal,:float, :integer, :string, :text, :time, and :timestamp.
如:add_column :表名, :column名, :类型
对列的属性设置
:null => true or false //是否允许空
:limit => size //列的长度
:default => value //默认值
decimal类型时候,:precision and :scale 用于设置精度
重命名列
rename_columnrders, :e_mail, :customer_email
修改列属性
change_columnrders,rder_type, :string
重命名表,注意对原有的model代码也会修改
rename_tablerder_histories,rder_notes
当添加一些不允许修改的表信息时,可以在self.down中抛出异常,防止错误的修改,导致数据丢失
def self.down
raise ActiveRecord::IrreversibleMigration
end
对表的创建,注意block的使用
def self.up
create_tablerder_histories do |t|
t.integerrder_id, :null => false
t.text :notes
t.timestamps
end
end
定义索引,这里并不很了解,建议需要时查看API
add_indexrders, :name,:unique => true
orders 为表名称
:name => "somename" 用于指定类名,默认为
unique表示不允许重复
rails创建表时,会自动创建名称为id的主键,也可以自定义
create_table :tickets, :primary_key => :number do |t|...end
创建不包含主键的表
create_table :authors_books, :id => false do |t|..end
可以通过在migration中创建对数据库的增加数据操作,来为测试提供便利,不过感觉数据可能会因此被
固化在migration中,违反了原来的初衷
Loading Data from Fixtures
可以通过定义一些保存数据的yml文件,专门保存数据的内容,然后使用migration进行加载
def self.up
down //调用当前的down操作,用于清除数据
directory = File.join(File.dirname(__FILE__), 'dev_data' ) //dev_data用于保存数据yml文件的目录
Fixtures.create_fixtures(directory, "users" )//加载该目录下的users.yml文件
end
def self.down
User.delete_all
end
注意需要引入所需的类
require 'active_record/fixtures'
yml中的格式如下
mike:
name: Mike Clark
status: admin
不过上诉方式,只建议用于加载在开发环境和生产环境下都需要使用的数据,如果要用于加载测试数据,可以用
rake的任务实现
一些时候,比如在修改列的类型,也可以通过在数据库中更新列值,来避免有可能出现的数据丢失
Product.update_all("price = price * 100" )
change_column :products, :price, :integer
使用原生的sql语句
create_table :line_items do |t|
t.integer :product_id, :null => false,ptions =>
"CONSTRAINT fk_line_item_products REFERENCES products(id)"
execute %{
CREATE TRIGGER #{constraint_name}_delete
BEFORE DELETE ON #{to_table}
FOR EACH ROW BEGIN
SELECT
RAISE(ABORT, "constraint violation: #{constraint_name}" )
WHERE
(SELECT id FROM #{from_table} WHERE #{from_column} = OLD.id) IS NOT NULL;
END;
}
对model类的控制
class Sheep < ActiveRecord::Base
set_table_name "sheep" #手动设置表名
end
也可以使用self.table_name = "sheep"
在model中也比较特别的一点,就是在model中并不能看到表中的属性,也就是看不到所对应的映射属性,当却可以被正常使用和显示,因为在创建migration时,rails将会自动保存这些信息,如果直接使用scaffold时,也可以自动创建所有的信息.所以并不会重复在model class中显示,包括id
如果需要添加属性,可以通过新建migration来使用
可以通过在命令台执行
ruby script/console
Order.column_names 来查看Order model内的列名
对于Boolean值的使用.因为数据库本身的有些支持Boolean,有些则需要使用int或char代替
建议使用user.superuser?进行判断,注意?的使用
然后在model定义该方法,superuser,返回对内部字符的判断返回结果,而不直接依赖数据库中属性
自定义主键列,默认会使用自增的Integer作为主键列,并且使用id进行索引
class LegacyBook < ActiveRecord::Base
self.primary_key = "isbn"
end
在设置值时,需要使用.id进行设置值,当访问时,使用设置的列名进行访问,使用id来读,使用列名来取,并且保持唯一
在model中类,因为都是继承ActiveRecord类中,所以也会默认使用你所配置的数据库连接
也可以在model中进行覆盖
establish_connection(
:adapter => "mysql" ,
:host => "dbserver.com" ,
:database => "backend" ,
:username => "chicho" ,
:password => "piano" )
CRUD操作
使用model类的
Model.new创建一个新的对象,设置属性后,调用save就可以保存
也可以使用block的方式
Order.new do |o|
o.name = "Dave Thomas"
# . . .
o.save
end
也可以通过hash的形式构建对象,在调用save更新到数据库
an_order = Order.new(
:name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check" )
an_order.save
与Hibernate类似,save后,该对象也自动会有id出现
从表单参数中直接创建对象
order = Order.new(params[:order]) //form名字为order
使用create保存对象,无须调用save方法
an_order = Order.create(
:name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check" )
其实这里的save方法可以理解成hibernate中的saveorupdate方法
create方法可以从array中直接保存一组对象到数据库中
orders = Order.create(
[ { :name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check"
},
{ :name => "Andy Hunt" ,
:email => "andy@pragprog.com" ,
:address => "456 Gentle Drive" ,
:pay_type => "po"
} ] )
查找对象的方式
Order.find(27) //使用id进行搜索
product_list = params[:product_ids]
Product.find(product_list).sum(&:price) 从一组id中获取对象,并计算其中的price属性
Person.find(:first, :conditions=>"name=’Dave’") 带条件的find
Give me the first person row that has the name Dave.”
也可以使用:all代替first,表示搜索全部
conditions中带上and ,可以附带更多的搜索条件,其实也就是在sql中带上where从句,注意引号的使用
在参数中,使用#{}带上ruby变量
:conditions => "name = '#{name}' and pay_type = 'po'"
注意以上方法,有可能导致注入的发生
使用?的形式,设置参数
pos = Order.find(:all,:conditions => ["name = ? and pay_type = 'po'" , name])
使用key的形式,设置参数
pos = Order.find(:all,:conditions => ["name = :name and pay_type = :pay_type" ,{:pay_type => pay_type, :name => name}])
注意这里的conditions的两种形式字符串与[]数组,其中数组形式的就省去and的使用.会自动进行组合
使用like子句
User.find(:all, :conditions => ["name like ?" , params[:name]+"%" ]).
不能直接使用?+字符串的%拼接
find()中的其他参数
:order sql中的order子句字符串
:limit 在使用:all时,限制返回的数量
:offset 用于分页时,可以限制返回的数据开始的位置:offset => page_num*page_size
:joins sql中的join子句
:joins => "as li inner join products as pr on li.product_id = pr.id"
注意:model提供了许多对外键操作的映射方式,所以并不需要经常自定义joins
:select 返回需要的列,其实也就是sql中的select中的列
:select => "*, a.name" //用于多表join查询时
:readonly 只读的查询方式
:from 代替table表名的查询方式
:group sql的分组子句 :group => "sku"
:lock 设置锁,太麻烦,不研究
使用自定义的sql语句
orders = LineItem.find_by_sql("select line_items.* from line_items, orders where order_id = orders.id and orders.name = 'Dave Thomas' " )
只要写出标准的格式,rails会自动完成映射,也可以理解成封装成hash的形式,访问时直接使用order.列名进行访问即可
也可以扩展成带参数形式的sql
Order.find_by_sql(["select * from orders where amount > ?" ,params[:amount]])
还提供了对多种列的统计
average = Order.average(:amount) # average amount of orders
max = Order.maximum(:amount)
min = Order.minimum(:amount)
total = Order.sum(:amount)
number = Order.count
注意ruby中方法调用时,可以省略掉()
result = Order.maximum :amount,
:group => "state" ,
:limit => 3,
rder => "max(amount) desc"
count的扩展
result1 = Order.count ["amount > ?" , minimum_purchase]
Order.count :conditions => "amount > 10" ,:group => "state"
也可以使用自定义的sql语句,注意方法的不同
count = LineItem.count_by_sql("sql...")
动态方法查询,rails提供了多种语义丰富的方法,便于理解和使用
order = Order.find_by_name("Dave Thomas" )
orders = Order.find_all_by_name("Dave Thomas" )
orders = Order.find_all_by_email(params['email' ])
使用!感叹号,用于在查找不到对象时,抛出异常,而不是返回nil
order = Order.find_by_name!("Dave Thomas" )
更丰富的动态方法
user = User.find_by_name_and_password(name, pw) #多列条件查询
还有更多语义丰富的方法
User.find_all_by_name
Cart.find_or_initialize_by_user_id(user.id)
可以通过在model内部添加name_scope,为model添加更多的动态方法
named_scope :last_n_days, lambda { |days| :condition =>['updated < ?' , days] }
调用:orders = Orders.last_n_days(7)
重载加载数据库对象,用于读取出一个对象后,更新该对象为最新的数据库中的属性
Object.reload
更新数据
save方法已经介绍,会自动判断新建还是更新
update属性方法,使用hash的参数形式
order.update_attributes(:name => "Barney",:email => "barney@bedrock.com" )
常用的还是update 和update_all方法
order = Order.update(12, :name => "Barney" , :email => "barney@bedrock.com" ) #,12为id
result = Product.update_all("price = 1.1*price" , "title like '%Java%'" )
save与create方法的!版本
失败都会抛出异常,成功则返回true与完整的record对象
删除数据
Order.delete(123) #id
User.delete([2,3,4,5]) #id
Product.delete_all(["price > ?" , @expensive_price]) #条件
order.destroy //单个对象,实例级别方法
Order.destroy_all(["shipped_at < ?" , 30.days.ago]) //类级别方法
将Ruby对象序列化到数据库中
class Purchase < ActiveRecord::Base
serialize :last_five #声明为存储序列化数据
# ...
end
写入
purchase.last_five = [ 'shoes' , 'shirt' , 'socks' , 'ski mask' , 'shorts' ]
purchase.save
读取时,将会自动转换成ruby的数组对象,注:列的类型最好为text
将一张表存放在不同的对象之中
class Customer < ActiveRecord::Base
composed_of :name, :class_name => 'Name' , ...
end
其中name为单独的一个class,并不继承activerecord类
注意其构造函数和内置属性,必须能否与表名内的列名对应
def initialize(first, initials, last)
@first = first
@initials = initials
@last = last
end
也可以手动指定所需的列名与字段的映射
composed_of :name,:class_name => "Name" ,
:mapping =>[ # database ruby
%w[ first_name first ], #列名,属性名
%w[ initials initials ],
%w[ last_name last ]
]
使用底层的sql连接,来执行sql,并且返回结果
res = Order.connection.select_all("select id, quantity*unit_price as total from line_items" )
将会返回hash形式的对象数组
注意使用自定义的sql查询时,默认将不会返回id,有此可能造成id确实,update变成create
注意一些rails在table中定义的保留字段的列
created_at, created_on, updated_at, updated_on //记录相关日期
lock_version //锁
id //默认生成的主键
xxx_id //外键中使用
xxx_count //保存子表的字段数目
position //acts_as_list使用时
parent_id //acts_as_tree使用时
type //单表继承使用时
rails也提供了一系列的方法,跟踪对象的变化情况..changed?,name_change等.
类似hibernate,rails也提供了查询的缓存
在rails中也可以通过在表中手动创建_id的外键列方式,来维护主外键关系,注意可以通过创建index,来提高join查询时的性能
常见的关系配置
One-to-One
A:belongs_torder
B:has_one :invoice
One-to-Many
A:belongs_torder #一方
B:has_many :line_items #多方
Many-to-Many
A:has_and_belongs_to_many :products
B:has_and_belongs_to_many :categories
无须关心中间表的配置
belongs_to,用于在多方设置,或者理解成外键一方
Declaration in child Foreign Key Parent Class Parent Table
belongs_to :product product_id Product products
belongs_to :invoice_item invoice_item_id InvoiceItem invoice_items
belongs_to :paid_order,
:class_name => "Order" ,
:foreign_key => "order_id" ,
:conditions => "paid_on is not null"
has_one: 在一方设置,属于一对一关系
Declaration Foreign Key Target Class Target Tabl
has_one :invoice order_id Invoice invoices
可以使用 :dependent => :destroy 设置级联
has_many:用于设置在一方,表示拥有多个元素
Declaration Foreign Key Target Class Target Table
has_many :line_items order_id LineItem line_items
高级设置,可以配置sql查询的方式
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%'"
还可以设置
:order => "quantity, unit_price DESC"
多表查询时,可以使用:uniq => true属性,来防止出现重复的数据
或者:select => "distinct users.*"
对象生命周期
Object Life Cycle
Validation 验证
在model进行save等操作时,都会自动执行验证
也可以自定义进行设置,不同情况下验证的方法
class User < ActiveRecord::Base
validate :valid_name?
validate_on_create :unique_name?
private
def valid_name?
unless name && name =~ /^\w+$/
errors.add(:name, "is missing or invalid" )
end
end
进行验证的时候,注意判断的方法,可以用使用带?的方法,将返回true,而不会跑出异常或者nil
内置的一些验证helper方法
格式验证
validates_format_of :name,
:with => /^\w+$/,
:message => "is missing or invalid
唯一验证
validates_uniqueness_of :name,
n => :create, #表示开启时机
:message => "is already being used" #错误信息
验证被选择
validates_acceptance_of :terms,
:message => "Please accept the terms to proceed"
对相关对象进行验证
validates_associated :line_items,
:message => "are messed up"
validates_associated :user
验证指定格式字段的值相同, //常用于密码验证
validates_confirmation_of :password
注意html的name属性
<%= password_field "user" , "password" %><br />
<%= password_field "user" , "password_confirmation" %><br />
循环验证属性 使用block
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
对集合中内容进行过滤验证
validates_exclusion_of :genre,
:in => %w{ polka twostep foxtrot },
:message => "no wild music allowed"
格式验证,也是使用正则
validates_format_of :length, :with => /^\d+(in|cm)/
验证集合必须包含内容
validates_inclusion_of :gender,
:in => %w{ male female },
:message => "should be 'male' or 'female'"
验证长度
validates_length_of :name, :maximum => 50
validates_length_of :password, :in => 6..20
验证数据格式
validates_numericality_of :age,nly_integer => true
validates_numericality_of :height_in_meters
非空的属性验证
validates_presence_of :name, :address
验证大小,与length长度使用一致
validates_size_of
验证值的唯一
validates_uniqueness_of :name, :scope => "group_id" //可以设置验证的域
Callbacks 回调函数,也可以理解成监听ActiveRecord操作后,自动执行的方法
使用的方式,只要在class中重载这些方法即可, 如:
def before_save
self.payment_due ||= Time.now + 30.days
end
也可以使用类似validate的方式,使用自定义的函数
before_validation :normalize_credit_card_number
protected //注意域
def normalize_credit_card_number
self.cc_number.gsub!(/[-\s]/, '' )
end
也可以使用
after_create do |order|
logger.info "Order #{order.id} created"
end
Observers的使用
ActiveRecord::Observer
可以用于监视指定的model类,而无须写入在model中,也提供了复用
根据约定大于配置
OrderObserver将会自动作用于名称为Order的类
如果需要手动控制同时控制多个类,可以使用以下方法
observe Order, Payment, Refund
默认情况下 observer类也放置在model目录下
默认情况下,Active record对象执行查询时,会用hash的方式从数据库中得到对象,再封装到column对象中,如果要自己定义查询时,如.find_by_sql,那么返回的将会是以数组形式保存的hash对象,访问的时候,默认hash的key与sql中的列名相关,也可以使用as语句来进行简化
缓存对象,具体用途不知
def length
# ...
end
memoize :length
Transactions 事务
事务的使用 ,手动调用方式
Account.transaction do
account1.deposit(100)
account2.withdraw(100)
end
乐观锁 省略....
Action Controller: Routing and URLs
默认的路由设置 Routing Requests
config/routes.rb 文件中 ,如果符合路由设置,将会默认将参数对应的保存在@params变量中,使用hash方式
自定义路由规则时,可以使用script/console 进行测试
depot> ruby script/console
>> rs = ActionController::Routing::Routes
>> rs.recognize_path "/store"
将会打印出匹配的route规则
如果更新文件后,需要使用下面命令进行加载
>> load "config/routes.rb"
map.connect用于设置单条规则,使用方法参数的方式设置参数
在route中,设置了一些默认值,用于对不完整URL的补充
defaults => { :action => "index" , :id => nil }
必须匹配规则
:requirements => { :name =>/regexp/, ...}
条件
:conditions => { :name =>/regexp/orstring, ...}
例子
map.connect 'store/checkout' ,
:conditions => { :method => :get },
:controller => "store" ,
:action => "display_checkout_form"
也可以进一步对匹配的内容,进行再验证
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
生成符合指定route规则的url
@link = url_for(:controller => "store" , :action => "display" , :id => 123)
其他的依据路由设置,来便捷实用url的方式
redirect_to(:action => 'delete' , :id => user.id)
可以方便的为model类添加route的rest效果
map.resources :articles # articles为model类名
Rails中controller的方法定义
index 返回model的集合,包含多个对象
create 创建一个model对象,保存到数据库中 POST
new 创建一个新资源,当并不保存到数据库中,返回给客户端进行填充
show 根据唯一的条件,返回符合该条件的唯一对象model
update根据id更新自定内容 _POST
edit 返回根据ID提取出来的内容,填充到界面的编辑表单中
destory 根据id,销毁对象
上诉的操作,都能包含了简单的CRUD操作
route中限制controller中action的方式
map.resources :comments, :except => [:update, :destroy]
这里还是回顾一下.使用内置的scaffold生成包括model在内的rest服务
ruby script/generate scaffold article title:string summary:text content:text
controller中创建的环境变量
action_name 当前所处的action名称
cookies cookie中的内容,可以进行读写
headers 一组用hash保存的http请求中的头信息,只用于返回使用,不用来编写cookie
params 保存提交上来的参数,form and url
request 获取请求的信息,包括http方法等
可以用于访问 protocol://host:port/path?query_string. 对应的所有属性
也可以只用其中的属性,获取客户端信息 request.env['HTTP_ACCEPT_LANGUAGE' ]
包括大量属性的使用,建议有需要的时候直接查看API
response ,保存http请求返回内容
session, 会话
填充模板的方法
render() 方法,用于执行填充操作,如果不附带参数,将会自动填充对应的action的模板界面
render(:text =>string) ,使用text为key,添加指定的内容要模板中
render(:inline =>string, [ :type =>"erb"|"builder"|"rjs" ], [ :locals =>hash] )
添加更详细的参数,可以选择要填充的模板类型
render(:action =>action_name) 调用其他的action模板,注意不会调用其他的action方法
render(:file =>path, [ :use_full_path =>true|false], [:locals =>hash]) 填充指定的模板
render(:template =>name, [:locals =>hash] ) 转发向指定的action,跨controller
render(:partial =>name, ...) 填充部分模板
render(:nothing => true) 返回空内容给浏览者
render(:xml =>stuff ) 填充指定的内容为xml,同样会设置Application/xml
render(:json =>stuff, [callback =>hash] ) ,返回内容给json,当后面函数未知
render(:update) do |page| ... end 使用block的方式填充一个类似rjs的模板
render还附带了一些通用的参数 :status, :layout, and :content_type
:status,用于返回http状态码,正常的为200,不建议返回30x
:layout 布尔值,用于设置是否使用模板,似乎还能用于选择其他布局文件
:content_type 设置Content-Type HTTP header
返回其他内容,或者字符的方式
send_data
send_data(data, options...)
如:send_data(png_data, :type => "image/png" , :disposition => "inline" )
send_file
send_file(path, options...) 将指定的文件发送给客户端
send_file("/files/secret_list" )
Redirects 重定向, 常见的http status code 为301, or 307
redirect_to(:action => 'display'), 如果要传递变量,可以使用flash域进行保存与读取
redirect_to("/help/order_entry.html") 跳转指定的url
redirect_to(:action => ..., options...) 跳转指定的action
返回上一页的请求 ----HTTP_REFERER中获取信息
redirect_to(:back)
修改头信息,并重定向
headers["Status" ] = "301 Moved Permanently"
redirect_to("http://my.new.home" )
Cookies and Sessions
操作cookie的例子
cookies[:marsupial] = { :value => "wombat" ,:expires => 30.days.from_now,:path => "/store" }
可以在controller中,对session进行设置
sessionff,nly => %w{ fetch_rss fetch_atom }
rails中有多种对session的存储机制
session_store = :cookie_store 默认的存储机制,在2.0后使用特别的格式进行存储,可以保存任何对象,限制为4k的存储上限
session_store = :p_store
存储在一个flat文件中,使用PStore format格式,可以在environment.rb文件中进行设置文件保存目录
config.action_controller.session_store = CGI::Session::PStore
config.action_controller.session_options[:tmpdir] = "/Users/dave/tmp"
config.action_controller.session_options[:prefix] = "myapp_session_"
session_store = :active_record_store
存储在数据库中
rake db:sessions:create //在数据库中创建所需的表
session_store = :drb_store
使用Ruby的DRb协议,允许在ruby进程之间共享对象,存储在drb服务中,独立web服务
session_store = :mem_cache_store
存储在memcached中
session_store = :memory_store
存储在内存中,对于ruby并不是一个好的处理方法
session_store = :file_store
存储在文件中,但只能保存字符串
可以在controller或者action中 开关session的使用
sessionff
也可以附带更多参数
sessionff,nly => [ :show, :list ]
sessionff, :if => proc { Time.now.wday == 0 }
Flash: Communicating Between Actions
flash,用于在action之间传递参数,是指在重定向操作时,可以将对象保存在flash中进行传递
flash.keep() 可以将flash内的值持久保存在session中,可以带参数保存指定的key对象
Filters and Verification 过滤与验证
rails支持三种类型的过滤器before, after, and around,都是使用def的方法,经过配置规则进行调用
Before and After Filters 使用
before_filter :authorize, :except => :login
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin' , :action => 'login'
end
end
也可以通过block与class的形式,设置filter
before_filter do |controller|
logger.info("Processing #{controller.action_name}" )
end
after_filter AuditFilter
class AuditFilter
def self.filter(controller)
AuditLog.create(:action => controller.action_name)
end
end
after filter常用于修改返回的内容,比如压缩返回的字符,修改头信息
Around Filters
around_filter :time_an_action
def time_an_action
started = Time.now
yield //用于执行代码块
elapsed = Time.now - started
logger.info("#{action_name} took #{elapsed} seconds" )
end
同样也可以使用class和block的形式进行设置
这里使用class实例的设置方式
class TimingFilter
def filter(controller)
started = Time.now
yield
elapsed = Time.now - started
controller.logger.info("#{controller.action_name} took #{elapsed} seconds" )
end
end
around_filter TimingFilter.new //注意这里使用的是实例
当同时使用两个around_filter时, 执行的顺序为 1 2 .. 2 1
filter可以被子类继承,也可以被重写覆盖
Verification验证
区别于对于字段属性的验证, 是用于权限验证的机制
verifynly => :post_comment, #action 名称
:session => :user_id, #session中的key
:add_flash => { :note => "You must log in to comment" }, #错误信息,添加到flash中
:redirect_to => :index #重定向的action 名称
过滤设置
:only =>:name or [ :name, ... ]
Verifies only the listed action or actions.
:except =>:name or [ :name, ... ]
Verifies all actions except those listed.
可以进行判断的内容
:flash =>:key or [ :key, ... ]
:method =>:symbol or [ :symbol, ... ] #http 请求方法
:params =>:key or [ :key, ... ] #请求的参数
:session =>:key or [ :key, ... ]
:xhr => true or false #是否为ajax请求
Actions 添加值进行传递
:add_flash =>hash
:add_headers =>hash #均为:key=>value
:redirect_to =>params #使用指定的hash进行重定向
:render =>params #使用指定参数进行渲染设置
Caching 缓存
rails提供了三种缓存 page caching , action caching ,fragment caching,
设置的方式也很简单,只要添加action即可
caches_page :public_content
caches_action :premium_content
默认情况下,只有在production环境下才开启缓存,可以通过设置调整
ActionController::Base.perform_caching = true | false
config.action_controller.perform_caching = true
对于page的缓存,使用基于url的机制控制页面缓存
清理缓存的方式
expire_page :action => "public_content"
expire_action :action => "premium_content" , :id => article
配置缓存策略
多服务器情况下,使用一台专门的服务器放置缓存文件,通过局域网进行读取
ActionController::Base.cache_store = :file_store, "#{RAILS_ROOT}/cache"
sweeper 用于专门清理缓存内容的类
app/sweepers:
导入使用:
cache_sweeper :article_sweeper,
nly => [ :create_article,
:update_article,
:delete_article ]
设置客户端缓存
在controller中可以设置Expires header
expires_in 20.minutes
expires_in 1.year
相应的再Apache中,也需要通过配置对于的扩展名添加缓存的http header
ExpiresActive On
<FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
</FilesMatch>
LastModified and ETag Support
304 Not Modified
不过似乎用于只读的使用,没有太大意义,忽略之
使用get获取数据,使用post提交数据,注意方法的使用
Action View
填充的方式
render(:action => 'fake_action_name' )
render(:template => 'controller/name' )
render(:file => 'dir/template' )
rails支持三种模板
builder 用于构建xml的返回内容
erb 用于生成html内容
rjs 用于生成JavaScript内容
environment.rb中配置如下,用于修改erb界面中,设置标签的类型 默认为>
<% 3.times do %>
Ho!<br/>
<% end %>
config.action_view.erb_trim_mode = "%"
% 5.downto(1) do |i|
<%= i %>... <br/>
% end
对encode后的参数读取
<%=h params[:name] %> #h的使用
Helpers 的使用,针对controller,可以将部分方法抽取到对于的helper后,直接在页面上使用,减少标签的代码
module StoreHelper
def page_title
@page_title || "Pragmatic Store"
end
end
<h3><%= page_title %></h3>
rails也提供了大量内置的helper,主要为格式化字符串提供了便利
如:
<%= number_to_percentage(66.66666, :precision => 1) %>
66.7%
在开发环境下 也可以使用debug获取参数的信息
<%= debug(params) %>
Linking to Other Pages and Resources 连接其他资源,提供了一些便利的方法
<%= link_to "Add Comment" , :action => "add_comment" %>
<%= link_to "Delete" , { :action => "delete" , :id => @product},
{ :class => "dangerous" ,
:confirm => "Are you sure?" ,
:method => :delete}
%>
提供了很详细的设置
绝对路径的连接
<%= link_to("Help" , "http://my.site/help/index.html" ) %>
还包括了对mail,css等文件的链接生成方式
可以通过安装'will_paginate的gem,为rails添加分页功能
表单的使用 ,(多种)
form_for
<% form_for :product, :url => { :action => :create } do |form| %>
<p>Title: <%= form.text_field :title, :size => 30 %></p>
<p>Description: <%= form.text_area :description, :rows => 3 %></p>
<p>Image URL: <%= form.text_field :image_url %></p>
<p>Price: <%= form.text_field :price, :size => 10 %></p>
<%= form.select :title, %w{ one two three } %>
<p><%= submit_tag %></p>
<% end %>
<% form_for :product,
:url => { :action => :create, :id => @product },
:html => { :class => "my_form" , :method => :put } do |form| %>
表单字段
Text
form.text_field(:attribute, options)
form.hidden_field(:attribute, options)
form.password_field(:attribute, options)
Text Areas
form.text_area(:attribute, options)
Radio Buttons
form.radio_button(:attribute, tag_value, options)
Checkboxes
form.check_box(:attribute, options, on_value, off_value)
Selection Lists
form.select(:attribute, choices, options, html_options)
如:
<% form_for :user do |form| %>
<%= form.select(:name, %w{ Andy Bert Chas Dave Eric Fred }) %>
<% end %>
也提供了内置对时间等组件
Multiple Models in a Form
显示model的值
<% form_for :user do |form| %>
Name: <%= form.text_field :name %>
通过建立model级别的表关系,可以直接在form中对多表进行直接的处理
scaffold.css文件保存了许多样式设置,可以通过重写,或者自定义的覆盖,来达到自定义的效果
rails 使用Layouts,最大程度的减少了常见的页面内容重复
<%= yield :layout %> 用于在layout中加载内容
默认会使用同名的layout,也可以在controller中进行自定义
layout "standard"
layout "standard" , :except => [ :rss, :atom ]
通过方法,动态选择layout
def determine_layout
if Store.is_closed?
"store_down"
else
"standard"
end
end
不适用layout的填充
render(:partial => 'article' ,
bject => @an_article,
:locals => { :authorized_by => session[:user_name],
:from_ip => request.remote_ip })
使用layout的填充
<%= render :partial => "user" , :layout => "administrator" %>
共享的填充模板
<%= render("shared/header" , :title => @article.title) %>
<%= render(:partial => "shared/post" ,bject => @article) %>
部分页面的缓存设置
<% cache do %> <!-- Here's the content we cache -->
<ul>
<% for article in Article.find_recent -%>
<li><p><%= h(article.body) %></p></li>
<% end -%>
</ul>
<% end %>
清理片段缓存的方式
<% cache(:action => 'list', :part => 'articles') do %>
<ul>
<% for article in @articles -%>
<li><p><%= h(article.body) %></p></li>
<% end -%>
</ul>
<% end %>
清理:expire_fragment(:action => 'list' , :part => 'articles' )
缓存机制选项
ActionController::Base.cache_store = <one of the following>
:memory_store,
:file_store, "/path/to/cache/directory"
:drb_store, "druby://localhost:9192"
:mem_cache_store, "localhost" ActionController::Base.cache_store =MyOwnStore.new("parameter")
标签生成的form格式
<input type="text" name="user[password]" />
ssl_requirement gem用于提供ssl的https连接
对于ODBC的连接SQL数据库,需要进行不少的设置,包括控制面板内的管理工具,设置本地的dsn设置
创建rails应用后,可以通过rake db:migrate检查是否配置完成,也可以使用idea来执行判断
数据库database.yml配置如下
development:
adapter: sqlserver
mode: odbc
dsn: CHENHENG
username : sa
password : 123
其他大体如上
controllers 目录下可以创建对应的c部分,里面创建的文件命名格式为
admin_controller.rb
访问时URL主体部分为admin/action,
其中action为方法名,可以通过直接定义def action来访问自定义的方法
方法执行完,会自动跳转views/admin/目录下的对应action.html.erb类似规则的文件
使用rails建立model时,会自动在db/migrate目录下创建rb文件,可以创建数据库所需的表信息
动态网页内容.两种方式
一:erb,
使用<%=...%>执行ruby,输出变量,与Jsp标签类似
使用<%%>执行ruby语句,循环等,注意end的使用 注意其中<% ...-%>格式的使用,似乎用于去除
所产生的空格
如果需要在<%=%>中输出带特殊字符的ruby代码,可以使用
<%= h("Ann & Bill <frazers@isp.email>" ) %>中的h()
获取action中定义的局部变量的方式@var...
在action中定义的@var变量,可以直接在erb文件中使用<%= @var %>读取
创建超链接的方式, //指向其他的URL,将会忽视对相对和绝对路径的URL处理
修改rails数据库环境的方式,切换development等..
rake db:create RAILS_ENV='development'
在使用Idea开发时,需要注意使用scaffold生成脚手架时,参数格式如下
product title:string desc:text
product为model的名称,即数据库中表的名称映射,一般会被映射成复数s的形式
title为列名,string为orm的类型
完整的指令应该为generate scaffold -f product title:string desc:text image_url:string
在开发时,注意不要存在多个不同版本的gem,idea会默认使用最高版本的gem,忽视原有的配置,
可以使用gem uninstall 进行卸载,包括所依赖的相关版本
为已存在的model添加属性,主要目的是为数据库添加列,并且增加所需的记录
generate migration -f add_price_to_product price:decimal
将会生成新的migrate文件,用于记录新增的记录,同时也提供了还原的方式
然后运行rake db:migrate 执行语句即可,如果要在对应的html中进行显示,可以使用
generate scaffold -f product title:string desc:text image_url:string
再次执行生成
添加验证,
在model中添加验证的方式
validates_presence_of :title, :description, :image_url //验证指定的字段非空
validates_numericality_of :price //验证字段必须为数字
添加自定义验证的方式
validate :price_must_be_at_least_a_cent
protected
def price_must_be_at_least_a_cent
errors.add(:price, 'should be at least 0.01' ) if price.nil? ||price < 0.01 //这里主要是errors的使用
end
通过正则进行定义验证的方式
validates_format_of :image_url,
:with => %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG or PNG image.'
通过数据库进行验证
validates_uniqueness_of :title
可以通过建立controller时,可以使用带参数,同时创建action,并且会自动生成对应的erb页面
<%=h ... %> 用于转换内容中的HTML代码
格式化价格
<%= sprintf("$%0.02f" , product.price) %>
货币格式转换的方式
<%= number_to_currency(product.price) %>
rails提供了两种用于超链接的标签
button_to 用于生成一个form,并且使用post的提交方法
link_to 用于生成一个简单的a href,使用get方式
创建基于rails本身的session解决数据存储方案
rake db:sessions:create //保存在数据库中
然后执行rake db:migrate ,创建所需的表
在rails2.3中,需要在config/initializers/session_store.rb中配置
Action_controller.session_store = :active_record_store
存储在数据库中,主要用于提供了一种跨多机器的存储环境
建立专属的controller
application_controller.rb //注意是必须的重写,内容可以参考框架下的实现,可以直接拷贝
从http请求中获取参数
params[:key]
Flash域,用于保存临时显示的数据,原理与struts2类似,同样保存在session中,自动删除
常用于保存错误信息
记录错误信息与flash的使用
logger.error("Attempt to access invalid product #{params[:id]}" )
flash[:notice] = "Invalid product"
redirect_to :action => 'index" //URL跳转,重定向,可以通过重构抽取相同的内容到方法中
读取flash的时候,加入if判断是否存在会更好一些
<% if flash[:notice] -%>
<div id="notice"><%= flash[:notice] %></div>
<% end -%>
判断指定域中对象是否为空的方式
if session[:counter].nil? ,也可以采取||=进行缩写
在页面中使用标签导入其他erb内容,类似jsp的include
<%= render(:partial => "cart_item" , :collection => @cart.items) %>
同时在目标中,可以直接包含循环体内容,而不需要重新循环读取
直接集合了c:foreach和include
其中partial为var ,collection为items. 不过功能应该更丰富一些
其中特殊的一点是,只要将需要嵌入的文件命名为_cart_item.html.erb即可自动寻找到,与partial属性相关
:object => @cart 用于传入一个对象
生成一个Ajax请求的标签
<% form_remote_tag :url => { :action => 'add_to_cart', :id => product } do %>
<%= submit_tag "Add to Cart" %>
<% end %>
rjs文件,用于生成所需的js模板文件,使用上与erb类似
在layout文件中,加入以下标签,用于导入默认所需的js文件
<%= javascript_include_tag :defaults %>
在rjs模板中同样适用标签进行声明
page.replace_html("cart" , :partial => "cart" ,bject => @cart)
表示替换调用页面中id=cart元素中的html内容
使用内置的effects.js 特效 其中:current_item 为html中元素的id
page[:current_item].visual_effect :highlight,
:startcolor => "#88ff88",
:endcolor => "#114411"
上述代码同样定义在rjs文件中
helpers/ 目录中保存了与controller同名的module文件,用于为对应的controller提供更多功能
将会被自动include,不需要手动编写
在进行渲染时,可以通过判断选择不同的方式
respond_to do |format|
format.js if request.xhr?
format.html {redirect_to_index}
end
在rails建立一对多的主外键关联
在module中添加
一方:has_many :line_items 后者为其他model
多方:belongs_torder 后者同上
application_controller 作用类似web.xml,用于用代码代替配置工程中的属性
before_filter :authorize, :except => :login 配置过滤器
其中的anthorize
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin' , :action => 'login'
end
end
:except 用于设置例外的界面或请求
创建基于xml的渲染器,类似erb,rjs
respond_to do |format|
format.html //会根据http header中Accept:内容的不同,自动选择不同的请求render
format.xml { render :layout => false } //false用于关闭使用layout模板
end
扩展名如下,使用时候比较特殊一些
who_bought.xml.builder
xml.order_list(:for_product => @product.title) do
for o in @orders
xml.order do
xml.name(o.name)
xml.email(o.email)
end
end
end
其他情况下,根据路由routes.rb的配置,可以直接使用扩展名,返回不同的渲染
map.connect ':controller/:action/:id.:format
使用内置自动生成xml文件
format.xml { render :layout => false ,:xml => @product.to_xml(:include =>rders) }
调用model的to_xml方法
生成指定格式的feed xml格式文件
format.atom { render :layout => false }
生成JSON 的格式,针对http header请求
format.json { render :layout => false ,:json => @product.to_json(:include =>rders) }
生成文档
rake doc:app
i18n/test跳过,不研究
rails项目的目录结构
doc/ 用于存放项目的说明文档
lib/ 可以用于放置一些rb类,可以被controller,view,model中引入,注意需要加上目录
lib/tasks, 用用于放置自定义的take任务
log/用于放置日志信息
public/放置一些静态文件,css,js等,以及404等错误html页面
script/开发用的脚本
vendor/存放第三方插件,代码,用于采用非全局的gem等,
使用项目gem rake rails:freeze:gems
使用系统gem rake rails:unfreeze
其他rake rails:freeze:edge
config / 目录 , 用于存放一些配置文件,数据库,环境等
ruby script/server -e development //切换运行环境,参数还包括test,production
config/database.yml 数据库连接的配置
Active Support
主要为model中的类,rails为其扩展了许多方便的方法
对于集合的操作,继承了Enumerable中的方法
groups = posts.group_by {|post| post.author_id}
state_lookup = us_states.index_by {|state| state.short_name}
total_orders = Order.find(:all).sum {|order| order.value }
rails也对Array进行了扩展
puts [ "ant" , "bat" , "cat" ].to_sentence #=> "ant, bat, and cat"
对String的扩展也很多...除了字符的截取,还提供了一些英文 单数,复数的转换,大小写格式化
扩展自己的语法转换规则
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular "goose" , "geese"
end
对数字同样也提供了扩展
提供了字节,时间的便捷操作
时间和日期的扩展
date = Date.today
puts date.tomorrow
以及更多的日期格式化获取
对Ruby语法的扩展,如方法调用
groups = posts.group_by {|post| post.author_id}
转化成
groups = posts.group_by(&:author_id) , 节约了临时对象的编写
Migrations
Rails中使用对Migration的维护,来对数据库进行DDL操作,同时对每次的处理,都使用单独的文件进行
保存,便于版本的控制,其中也会将当前项目的db信息保存在表schema_migrations table中
最常见的执行 rake db:migrate,将会比对当前数据库表中与文件的区别,进行执行
对db版本的控制
rake db:migrate VERSION=20080601000010 //将版本调整至指定版本,
rake db:migrate:redo STEP=3 //效果一致
常见的列类型,使用在Migration文件中的add_column:属性中
:binary, :boolean, :date, :datetime, :decimal,:float, :integer, :string, :text, :time, and :timestamp.
如:add_column :表名, :column名, :类型
对列的属性设置
:null => true or false //是否允许空
:limit => size //列的长度
:default => value //默认值
decimal类型时候,:precision and :scale 用于设置精度
重命名列
rename_columnrders, :e_mail, :customer_email
修改列属性
change_columnrders,rder_type, :string
重命名表,注意对原有的model代码也会修改
rename_tablerder_histories,rder_notes
当添加一些不允许修改的表信息时,可以在self.down中抛出异常,防止错误的修改,导致数据丢失
def self.down
raise ActiveRecord::IrreversibleMigration
end
对表的创建,注意block的使用
def self.up
create_tablerder_histories do |t|
t.integerrder_id, :null => false
t.text :notes
t.timestamps
end
end
定义索引,这里并不很了解,建议需要时查看API
add_indexrders, :name,:unique => true
orders 为表名称
:name => "somename" 用于指定类名,默认为
unique表示不允许重复
rails创建表时,会自动创建名称为id的主键,也可以自定义
create_table :tickets, :primary_key => :number do |t|...end
创建不包含主键的表
create_table :authors_books, :id => false do |t|..end
可以通过在migration中创建对数据库的增加数据操作,来为测试提供便利,不过感觉数据可能会因此被
固化在migration中,违反了原来的初衷
Loading Data from Fixtures
可以通过定义一些保存数据的yml文件,专门保存数据的内容,然后使用migration进行加载
def self.up
down //调用当前的down操作,用于清除数据
directory = File.join(File.dirname(__FILE__), 'dev_data' ) //dev_data用于保存数据yml文件的目录
Fixtures.create_fixtures(directory, "users" )//加载该目录下的users.yml文件
end
def self.down
User.delete_all
end
注意需要引入所需的类
require 'active_record/fixtures'
yml中的格式如下
mike:
name: Mike Clark
status: admin
不过上诉方式,只建议用于加载在开发环境和生产环境下都需要使用的数据,如果要用于加载测试数据,可以用
rake的任务实现
一些时候,比如在修改列的类型,也可以通过在数据库中更新列值,来避免有可能出现的数据丢失
Product.update_all("price = price * 100" )
change_column :products, :price, :integer
使用原生的sql语句
create_table :line_items do |t|
t.integer :product_id, :null => false,ptions =>
"CONSTRAINT fk_line_item_products REFERENCES products(id)"
execute %{
CREATE TRIGGER #{constraint_name}_delete
BEFORE DELETE ON #{to_table}
FOR EACH ROW BEGIN
SELECT
RAISE(ABORT, "constraint violation: #{constraint_name}" )
WHERE
(SELECT id FROM #{from_table} WHERE #{from_column} = OLD.id) IS NOT NULL;
END;
}
对model类的控制
class Sheep < ActiveRecord::Base
set_table_name "sheep" #手动设置表名
end
也可以使用self.table_name = "sheep"
在model中也比较特别的一点,就是在model中并不能看到表中的属性,也就是看不到所对应的映射属性,当却可以被正常使用和显示,因为在创建migration时,rails将会自动保存这些信息,如果直接使用scaffold时,也可以自动创建所有的信息.所以并不会重复在model class中显示,包括id
如果需要添加属性,可以通过新建migration来使用
可以通过在命令台执行
ruby script/console
Order.column_names 来查看Order model内的列名
对于Boolean值的使用.因为数据库本身的有些支持Boolean,有些则需要使用int或char代替
建议使用user.superuser?进行判断,注意?的使用
然后在model定义该方法,superuser,返回对内部字符的判断返回结果,而不直接依赖数据库中属性
自定义主键列,默认会使用自增的Integer作为主键列,并且使用id进行索引
class LegacyBook < ActiveRecord::Base
self.primary_key = "isbn"
end
在设置值时,需要使用.id进行设置值,当访问时,使用设置的列名进行访问,使用id来读,使用列名来取,并且保持唯一
在model中类,因为都是继承ActiveRecord类中,所以也会默认使用你所配置的数据库连接
也可以在model中进行覆盖
establish_connection(
:adapter => "mysql" ,
:host => "dbserver.com" ,
:database => "backend" ,
:username => "chicho" ,
:password => "piano" )
CRUD操作
使用model类的
Model.new创建一个新的对象,设置属性后,调用save就可以保存
也可以使用block的方式
Order.new do |o|
o.name = "Dave Thomas"
# . . .
o.save
end
也可以通过hash的形式构建对象,在调用save更新到数据库
an_order = Order.new(
:name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check" )
an_order.save
与Hibernate类似,save后,该对象也自动会有id出现
从表单参数中直接创建对象
order = Order.new(params[:order]) //form名字为order
使用create保存对象,无须调用save方法
an_order = Order.create(
:name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check" )
其实这里的save方法可以理解成hibernate中的saveorupdate方法
create方法可以从array中直接保存一组对象到数据库中
orders = Order.create(
[ { :name => "Dave Thomas" ,
:email => "dave@pragprog.com" ,
:address => "123 Main St" ,
:pay_type => "check"
},
{ :name => "Andy Hunt" ,
:email => "andy@pragprog.com" ,
:address => "456 Gentle Drive" ,
:pay_type => "po"
} ] )
查找对象的方式
Order.find(27) //使用id进行搜索
product_list = params[:product_ids]
Product.find(product_list).sum(&:price) 从一组id中获取对象,并计算其中的price属性
Person.find(:first, :conditions=>"name=’Dave’") 带条件的find
Give me the first person row that has the name Dave.”
也可以使用:all代替first,表示搜索全部
conditions中带上and ,可以附带更多的搜索条件,其实也就是在sql中带上where从句,注意引号的使用
在参数中,使用#{}带上ruby变量
:conditions => "name = '#{name}' and pay_type = 'po'"
注意以上方法,有可能导致注入的发生
使用?的形式,设置参数
pos = Order.find(:all,:conditions => ["name = ? and pay_type = 'po'" , name])
使用key的形式,设置参数
pos = Order.find(:all,:conditions => ["name = :name and pay_type = :pay_type" ,{:pay_type => pay_type, :name => name}])
注意这里的conditions的两种形式字符串与[]数组,其中数组形式的就省去and的使用.会自动进行组合
使用like子句
User.find(:all, :conditions => ["name like ?" , params[:name]+"%" ]).
不能直接使用?+字符串的%拼接
find()中的其他参数
:order sql中的order子句字符串
:limit 在使用:all时,限制返回的数量
:offset 用于分页时,可以限制返回的数据开始的位置:offset => page_num*page_size
:joins sql中的join子句
:joins => "as li inner join products as pr on li.product_id = pr.id"
注意:model提供了许多对外键操作的映射方式,所以并不需要经常自定义joins
:select 返回需要的列,其实也就是sql中的select中的列
:select => "*, a.name" //用于多表join查询时
:readonly 只读的查询方式
:from 代替table表名的查询方式
:group sql的分组子句 :group => "sku"
:lock 设置锁,太麻烦,不研究
使用自定义的sql语句
orders = LineItem.find_by_sql("select line_items.* from line_items, orders where order_id = orders.id and orders.name = 'Dave Thomas' " )
只要写出标准的格式,rails会自动完成映射,也可以理解成封装成hash的形式,访问时直接使用order.列名进行访问即可
也可以扩展成带参数形式的sql
Order.find_by_sql(["select * from orders where amount > ?" ,params[:amount]])
还提供了对多种列的统计
average = Order.average(:amount) # average amount of orders
max = Order.maximum(:amount)
min = Order.minimum(:amount)
total = Order.sum(:amount)
number = Order.count
注意ruby中方法调用时,可以省略掉()
result = Order.maximum :amount,
:group => "state" ,
:limit => 3,
rder => "max(amount) desc"
count的扩展
result1 = Order.count ["amount > ?" , minimum_purchase]
Order.count :conditions => "amount > 10" ,:group => "state"
也可以使用自定义的sql语句,注意方法的不同
count = LineItem.count_by_sql("sql...")
动态方法查询,rails提供了多种语义丰富的方法,便于理解和使用
order = Order.find_by_name("Dave Thomas" )
orders = Order.find_all_by_name("Dave Thomas" )
orders = Order.find_all_by_email(params['email' ])
使用!感叹号,用于在查找不到对象时,抛出异常,而不是返回nil
order = Order.find_by_name!("Dave Thomas" )
更丰富的动态方法
user = User.find_by_name_and_password(name, pw) #多列条件查询
还有更多语义丰富的方法
User.find_all_by_name
Cart.find_or_initialize_by_user_id(user.id)
可以通过在model内部添加name_scope,为model添加更多的动态方法
named_scope :last_n_days, lambda { |days| :condition =>['updated < ?' , days] }
调用:orders = Orders.last_n_days(7)
重载加载数据库对象,用于读取出一个对象后,更新该对象为最新的数据库中的属性
Object.reload
更新数据
save方法已经介绍,会自动判断新建还是更新
update属性方法,使用hash的参数形式
order.update_attributes(:name => "Barney",:email => "barney@bedrock.com" )
常用的还是update 和update_all方法
order = Order.update(12, :name => "Barney" , :email => "barney@bedrock.com" ) #,12为id
result = Product.update_all("price = 1.1*price" , "title like '%Java%'" )
save与create方法的!版本
失败都会抛出异常,成功则返回true与完整的record对象
删除数据
Order.delete(123) #id
User.delete([2,3,4,5]) #id
Product.delete_all(["price > ?" , @expensive_price]) #条件
order.destroy //单个对象,实例级别方法
Order.destroy_all(["shipped_at < ?" , 30.days.ago]) //类级别方法
将Ruby对象序列化到数据库中
class Purchase < ActiveRecord::Base
serialize :last_five #声明为存储序列化数据
# ...
end
写入
purchase.last_five = [ 'shoes' , 'shirt' , 'socks' , 'ski mask' , 'shorts' ]
purchase.save
读取时,将会自动转换成ruby的数组对象,注:列的类型最好为text
将一张表存放在不同的对象之中
class Customer < ActiveRecord::Base
composed_of :name, :class_name => 'Name' , ...
end
其中name为单独的一个class,并不继承activerecord类
注意其构造函数和内置属性,必须能否与表名内的列名对应
def initialize(first, initials, last)
@first = first
@initials = initials
@last = last
end
也可以手动指定所需的列名与字段的映射
composed_of :name,:class_name => "Name" ,
:mapping =>[ # database ruby
%w[ first_name first ], #列名,属性名
%w[ initials initials ],
%w[ last_name last ]
]
使用底层的sql连接,来执行sql,并且返回结果
res = Order.connection.select_all("select id, quantity*unit_price as total from line_items" )
将会返回hash形式的对象数组
注意使用自定义的sql查询时,默认将不会返回id,有此可能造成id确实,update变成create
注意一些rails在table中定义的保留字段的列
created_at, created_on, updated_at, updated_on //记录相关日期
lock_version //锁
id //默认生成的主键
xxx_id //外键中使用
xxx_count //保存子表的字段数目
position //acts_as_list使用时
parent_id //acts_as_tree使用时
type //单表继承使用时
rails也提供了一系列的方法,跟踪对象的变化情况..changed?,name_change等.
类似hibernate,rails也提供了查询的缓存
在rails中也可以通过在表中手动创建_id的外键列方式,来维护主外键关系,注意可以通过创建index,来提高join查询时的性能
常见的关系配置
One-to-One
A:belongs_torder
B:has_one :invoice
One-to-Many
A:belongs_torder #一方
B:has_many :line_items #多方
Many-to-Many
A:has_and_belongs_to_many :products
B:has_and_belongs_to_many :categories
无须关心中间表的配置
belongs_to,用于在多方设置,或者理解成外键一方
Declaration in child Foreign Key Parent Class Parent Table
belongs_to :product product_id Product products
belongs_to :invoice_item invoice_item_id InvoiceItem invoice_items
belongs_to :paid_order,
:class_name => "Order" ,
:foreign_key => "order_id" ,
:conditions => "paid_on is not null"
has_one: 在一方设置,属于一对一关系
Declaration Foreign Key Target Class Target Tabl
has_one :invoice order_id Invoice invoices
可以使用 :dependent => :destroy 设置级联
has_many:用于设置在一方,表示拥有多个元素
Declaration Foreign Key Target Class Target Table
has_many :line_items order_id LineItem line_items
高级设置,可以配置sql查询的方式
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%'"
还可以设置
:order => "quantity, unit_price DESC"
多表查询时,可以使用:uniq => true属性,来防止出现重复的数据
或者:select => "distinct users.*"
对象生命周期
Object Life Cycle
Validation 验证
在model进行save等操作时,都会自动执行验证
也可以自定义进行设置,不同情况下验证的方法
class User < ActiveRecord::Base
validate :valid_name?
validate_on_create :unique_name?
private
def valid_name?
unless name && name =~ /^\w+$/
errors.add(:name, "is missing or invalid" )
end
end
进行验证的时候,注意判断的方法,可以用使用带?的方法,将返回true,而不会跑出异常或者nil
内置的一些验证helper方法
格式验证
validates_format_of :name,
:with => /^\w+$/,
:message => "is missing or invalid
唯一验证
validates_uniqueness_of :name,
n => :create, #表示开启时机
:message => "is already being used" #错误信息
验证被选择
validates_acceptance_of :terms,
:message => "Please accept the terms to proceed"
对相关对象进行验证
validates_associated :line_items,
:message => "are messed up"
validates_associated :user
验证指定格式字段的值相同, //常用于密码验证
validates_confirmation_of :password
注意html的name属性
<%= password_field "user" , "password" %><br />
<%= password_field "user" , "password_confirmation" %><br />
循环验证属性 使用block
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
对集合中内容进行过滤验证
validates_exclusion_of :genre,
:in => %w{ polka twostep foxtrot },
:message => "no wild music allowed"
格式验证,也是使用正则
validates_format_of :length, :with => /^\d+(in|cm)/
验证集合必须包含内容
validates_inclusion_of :gender,
:in => %w{ male female },
:message => "should be 'male' or 'female'"
验证长度
validates_length_of :name, :maximum => 50
validates_length_of :password, :in => 6..20
验证数据格式
validates_numericality_of :age,nly_integer => true
validates_numericality_of :height_in_meters
非空的属性验证
validates_presence_of :name, :address
验证大小,与length长度使用一致
validates_size_of
验证值的唯一
validates_uniqueness_of :name, :scope => "group_id" //可以设置验证的域
Callbacks 回调函数,也可以理解成监听ActiveRecord操作后,自动执行的方法
使用的方式,只要在class中重载这些方法即可, 如:
def before_save
self.payment_due ||= Time.now + 30.days
end
也可以使用类似validate的方式,使用自定义的函数
before_validation :normalize_credit_card_number
protected //注意域
def normalize_credit_card_number
self.cc_number.gsub!(/[-\s]/, '' )
end
也可以使用
after_create do |order|
logger.info "Order #{order.id} created"
end
Observers的使用
ActiveRecord::Observer
可以用于监视指定的model类,而无须写入在model中,也提供了复用
根据约定大于配置
OrderObserver将会自动作用于名称为Order的类
如果需要手动控制同时控制多个类,可以使用以下方法
observe Order, Payment, Refund
默认情况下 observer类也放置在model目录下
默认情况下,Active record对象执行查询时,会用hash的方式从数据库中得到对象,再封装到column对象中,如果要自己定义查询时,如.find_by_sql,那么返回的将会是以数组形式保存的hash对象,访问的时候,默认hash的key与sql中的列名相关,也可以使用as语句来进行简化
缓存对象,具体用途不知
def length
# ...
end
memoize :length
Transactions 事务
事务的使用 ,手动调用方式
Account.transaction do
account1.deposit(100)
account2.withdraw(100)
end
乐观锁 省略....
Action Controller: Routing and URLs
默认的路由设置 Routing Requests
config/routes.rb 文件中 ,如果符合路由设置,将会默认将参数对应的保存在@params变量中,使用hash方式
自定义路由规则时,可以使用script/console 进行测试
depot> ruby script/console
>> rs = ActionController::Routing::Routes
>> rs.recognize_path "/store"
将会打印出匹配的route规则
如果更新文件后,需要使用下面命令进行加载
>> load "config/routes.rb"
map.connect用于设置单条规则,使用方法参数的方式设置参数
在route中,设置了一些默认值,用于对不完整URL的补充
defaults => { :action => "index" , :id => nil }
必须匹配规则
:requirements => { :name =>/regexp/, ...}
条件
:conditions => { :name =>/regexp/orstring, ...}
例子
map.connect 'store/checkout' ,
:conditions => { :method => :get },
:controller => "store" ,
:action => "display_checkout_form"
也可以进一步对匹配的内容,进行再验证
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
生成符合指定route规则的url
@link = url_for(:controller => "store" , :action => "display" , :id => 123)
其他的依据路由设置,来便捷实用url的方式
redirect_to(:action => 'delete' , :id => user.id)
可以方便的为model类添加route的rest效果
map.resources :articles # articles为model类名
Rails中controller的方法定义
index 返回model的集合,包含多个对象
create 创建一个model对象,保存到数据库中 POST
new 创建一个新资源,当并不保存到数据库中,返回给客户端进行填充
show 根据唯一的条件,返回符合该条件的唯一对象model
update根据id更新自定内容 _POST
edit 返回根据ID提取出来的内容,填充到界面的编辑表单中
destory 根据id,销毁对象
上诉的操作,都能包含了简单的CRUD操作
route中限制controller中action的方式
map.resources :comments, :except => [:update, :destroy]
这里还是回顾一下.使用内置的scaffold生成包括model在内的rest服务
ruby script/generate scaffold article title:string summary:text content:text
controller中创建的环境变量
action_name 当前所处的action名称
cookies cookie中的内容,可以进行读写
headers 一组用hash保存的http请求中的头信息,只用于返回使用,不用来编写cookie
params 保存提交上来的参数,form and url
request 获取请求的信息,包括http方法等
可以用于访问 protocol://host:port/path?query_string. 对应的所有属性
也可以只用其中的属性,获取客户端信息 request.env['HTTP_ACCEPT_LANGUAGE' ]
包括大量属性的使用,建议有需要的时候直接查看API
response ,保存http请求返回内容
session, 会话
填充模板的方法
render() 方法,用于执行填充操作,如果不附带参数,将会自动填充对应的action的模板界面
render(:text =>string) ,使用text为key,添加指定的内容要模板中
render(:inline =>string, [ :type =>"erb"|"builder"|"rjs" ], [ :locals =>hash] )
添加更详细的参数,可以选择要填充的模板类型
render(:action =>action_name) 调用其他的action模板,注意不会调用其他的action方法
render(:file =>path, [ :use_full_path =>true|false], [:locals =>hash]) 填充指定的模板
render(:template =>name, [:locals =>hash] ) 转发向指定的action,跨controller
render(:partial =>name, ...) 填充部分模板
render(:nothing => true) 返回空内容给浏览者
render(:xml =>stuff ) 填充指定的内容为xml,同样会设置Application/xml
render(:json =>stuff, [callback =>hash] ) ,返回内容给json,当后面函数未知
render(:update) do |page| ... end 使用block的方式填充一个类似rjs的模板
render还附带了一些通用的参数 :status, :layout, and :content_type
:status,用于返回http状态码,正常的为200,不建议返回30x
:layout 布尔值,用于设置是否使用模板,似乎还能用于选择其他布局文件
:content_type 设置Content-Type HTTP header
返回其他内容,或者字符的方式
send_data
send_data(data, options...)
如:send_data(png_data, :type => "image/png" , :disposition => "inline" )
send_file
send_file(path, options...) 将指定的文件发送给客户端
send_file("/files/secret_list" )
Redirects 重定向, 常见的http status code 为301, or 307
redirect_to(:action => 'display'), 如果要传递变量,可以使用flash域进行保存与读取
redirect_to("/help/order_entry.html") 跳转指定的url
redirect_to(:action => ..., options...) 跳转指定的action
返回上一页的请求 ----HTTP_REFERER中获取信息
redirect_to(:back)
修改头信息,并重定向
headers["Status" ] = "301 Moved Permanently"
redirect_to("http://my.new.home" )
Cookies and Sessions
操作cookie的例子
cookies[:marsupial] = { :value => "wombat" ,:expires => 30.days.from_now,:path => "/store" }
可以在controller中,对session进行设置
sessionff,nly => %w{ fetch_rss fetch_atom }
rails中有多种对session的存储机制
session_store = :cookie_store 默认的存储机制,在2.0后使用特别的格式进行存储,可以保存任何对象,限制为4k的存储上限
session_store = :p_store
存储在一个flat文件中,使用PStore format格式,可以在environment.rb文件中进行设置文件保存目录
config.action_controller.session_store = CGI::Session::PStore
config.action_controller.session_options[:tmpdir] = "/Users/dave/tmp"
config.action_controller.session_options[:prefix] = "myapp_session_"
session_store = :active_record_store
存储在数据库中
rake db:sessions:create //在数据库中创建所需的表
session_store = :drb_store
使用Ruby的DRb协议,允许在ruby进程之间共享对象,存储在drb服务中,独立web服务
session_store = :mem_cache_store
存储在memcached中
session_store = :memory_store
存储在内存中,对于ruby并不是一个好的处理方法
session_store = :file_store
存储在文件中,但只能保存字符串
可以在controller或者action中 开关session的使用
sessionff
也可以附带更多参数
sessionff,nly => [ :show, :list ]
sessionff, :if => proc { Time.now.wday == 0 }
Flash: Communicating Between Actions
flash,用于在action之间传递参数,是指在重定向操作时,可以将对象保存在flash中进行传递
flash.keep() 可以将flash内的值持久保存在session中,可以带参数保存指定的key对象
Filters and Verification 过滤与验证
rails支持三种类型的过滤器before, after, and around,都是使用def的方法,经过配置规则进行调用
Before and After Filters 使用
before_filter :authorize, :except => :login
protected
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "Please log in"
redirect_to :controller => 'admin' , :action => 'login'
end
end
也可以通过block与class的形式,设置filter
before_filter do |controller|
logger.info("Processing #{controller.action_name}" )
end
after_filter AuditFilter
class AuditFilter
def self.filter(controller)
AuditLog.create(:action => controller.action_name)
end
end
after filter常用于修改返回的内容,比如压缩返回的字符,修改头信息
Around Filters
around_filter :time_an_action
def time_an_action
started = Time.now
yield //用于执行代码块
elapsed = Time.now - started
logger.info("#{action_name} took #{elapsed} seconds" )
end
同样也可以使用class和block的形式进行设置
这里使用class实例的设置方式
class TimingFilter
def filter(controller)
started = Time.now
yield
elapsed = Time.now - started
controller.logger.info("#{controller.action_name} took #{elapsed} seconds" )
end
end
around_filter TimingFilter.new //注意这里使用的是实例
当同时使用两个around_filter时, 执行的顺序为 1 2 .. 2 1
filter可以被子类继承,也可以被重写覆盖
Verification验证
区别于对于字段属性的验证, 是用于权限验证的机制
verifynly => :post_comment, #action 名称
:session => :user_id, #session中的key
:add_flash => { :note => "You must log in to comment" }, #错误信息,添加到flash中
:redirect_to => :index #重定向的action 名称
过滤设置
:only =>:name or [ :name, ... ]
Verifies only the listed action or actions.
:except =>:name or [ :name, ... ]
Verifies all actions except those listed.
可以进行判断的内容
:flash =>:key or [ :key, ... ]
:method =>:symbol or [ :symbol, ... ] #http 请求方法
:params =>:key or [ :key, ... ] #请求的参数
:session =>:key or [ :key, ... ]
:xhr => true or false #是否为ajax请求
Actions 添加值进行传递
:add_flash =>hash
:add_headers =>hash #均为:key=>value
:redirect_to =>params #使用指定的hash进行重定向
:render =>params #使用指定参数进行渲染设置
Caching 缓存
rails提供了三种缓存 page caching , action caching ,fragment caching,
设置的方式也很简单,只要添加action即可
caches_page :public_content
caches_action :premium_content
默认情况下,只有在production环境下才开启缓存,可以通过设置调整
ActionController::Base.perform_caching = true | false
config.action_controller.perform_caching = true
对于page的缓存,使用基于url的机制控制页面缓存
清理缓存的方式
expire_page :action => "public_content"
expire_action :action => "premium_content" , :id => article
配置缓存策略
多服务器情况下,使用一台专门的服务器放置缓存文件,通过局域网进行读取
ActionController::Base.cache_store = :file_store, "#{RAILS_ROOT}/cache"
sweeper 用于专门清理缓存内容的类
app/sweepers:
导入使用:
cache_sweeper :article_sweeper,
nly => [ :create_article,
:update_article,
:delete_article ]
设置客户端缓存
在controller中可以设置Expires header
expires_in 20.minutes
expires_in 1.year
相应的再Apache中,也需要通过配置对于的扩展名添加缓存的http header
ExpiresActive On
<FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
</FilesMatch>
LastModified and ETag Support
304 Not Modified
不过似乎用于只读的使用,没有太大意义,忽略之
使用get获取数据,使用post提交数据,注意方法的使用
Action View
填充的方式
render(:action => 'fake_action_name' )
render(:template => 'controller/name' )
render(:file => 'dir/template' )
rails支持三种模板
builder 用于构建xml的返回内容
erb 用于生成html内容
rjs 用于生成JavaScript内容
environment.rb中配置如下,用于修改erb界面中,设置标签的类型 默认为>
<% 3.times do %>
Ho!<br/>
<% end %>
config.action_view.erb_trim_mode = "%"
% 5.downto(1) do |i|
<%= i %>... <br/>
% end
对encode后的参数读取
<%=h params[:name] %> #h的使用
Helpers 的使用,针对controller,可以将部分方法抽取到对于的helper后,直接在页面上使用,减少标签的代码
module StoreHelper
def page_title
@page_title || "Pragmatic Store"
end
end
<h3><%= page_title %></h3>
rails也提供了大量内置的helper,主要为格式化字符串提供了便利
如:
<%= number_to_percentage(66.66666, :precision => 1) %>
66.7%
在开发环境下 也可以使用debug获取参数的信息
<%= debug(params) %>
Linking to Other Pages and Resources 连接其他资源,提供了一些便利的方法
<%= link_to "Add Comment" , :action => "add_comment" %>
<%= link_to "Delete" , { :action => "delete" , :id => @product},
{ :class => "dangerous" ,
:confirm => "Are you sure?" ,
:method => :delete}
%>
提供了很详细的设置
绝对路径的连接
<%= link_to("Help" , "http://my.site/help/index.html" ) %>
还包括了对mail,css等文件的链接生成方式
可以通过安装'will_paginate的gem,为rails添加分页功能
表单的使用 ,(多种)
form_for
<% form_for :product, :url => { :action => :create } do |form| %>
<p>Title: <%= form.text_field :title, :size => 30 %></p>
<p>Description: <%= form.text_area :description, :rows => 3 %></p>
<p>Image URL: <%= form.text_field :image_url %></p>
<p>Price: <%= form.text_field :price, :size => 10 %></p>
<%= form.select :title, %w{ one two three } %>
<p><%= submit_tag %></p>
<% end %>
<% form_for :product,
:url => { :action => :create, :id => @product },
:html => { :class => "my_form" , :method => :put } do |form| %>
表单字段
Text
form.text_field(:attribute, options)
form.hidden_field(:attribute, options)
form.password_field(:attribute, options)
Text Areas
form.text_area(:attribute, options)
Radio Buttons
form.radio_button(:attribute, tag_value, options)
Checkboxes
form.check_box(:attribute, options, on_value, off_value)
Selection Lists
form.select(:attribute, choices, options, html_options)
如:
<% form_for :user do |form| %>
<%= form.select(:name, %w{ Andy Bert Chas Dave Eric Fred }) %>
<% end %>
也提供了内置对时间等组件
Multiple Models in a Form
显示model的值
<% form_for :user do |form| %>
Name: <%= form.text_field :name %>
通过建立model级别的表关系,可以直接在form中对多表进行直接的处理
scaffold.css文件保存了许多样式设置,可以通过重写,或者自定义的覆盖,来达到自定义的效果
rails 使用Layouts,最大程度的减少了常见的页面内容重复
<%= yield :layout %> 用于在layout中加载内容
默认会使用同名的layout,也可以在controller中进行自定义
layout "standard"
layout "standard" , :except => [ :rss, :atom ]
通过方法,动态选择layout
def determine_layout
if Store.is_closed?
"store_down"
else
"standard"
end
end
不适用layout的填充
render(:partial => 'article' ,
bject => @an_article,
:locals => { :authorized_by => session[:user_name],
:from_ip => request.remote_ip })
使用layout的填充
<%= render :partial => "user" , :layout => "administrator" %>
共享的填充模板
<%= render("shared/header" , :title => @article.title) %>
<%= render(:partial => "shared/post" ,bject => @article) %>
部分页面的缓存设置
<% cache do %> <!-- Here's the content we cache -->
<ul>
<% for article in Article.find_recent -%>
<li><p><%= h(article.body) %></p></li>
<% end -%>
</ul>
<% end %>
清理片段缓存的方式
<% cache(:action => 'list', :part => 'articles') do %>
<ul>
<% for article in @articles -%>
<li><p><%= h(article.body) %></p></li>
<% end -%>
</ul>
<% end %>
清理:expire_fragment(:action => 'list' , :part => 'articles' )
缓存机制选项
ActionController::Base.cache_store = <one of the following>
:memory_store,
:file_store, "/path/to/cache/directory"
:drb_store, "druby://localhost:9192"
:mem_cache_store, "localhost" ActionController::Base.cache_store =MyOwnStore.new("parameter")
标签生成的form格式
<input type="text" name="user[password]" />
ssl_requirement gem用于提供ssl的https连接
相关推荐
Ruby是一种动态、开源的编程语言,以其简洁、优雅的语法和强大的元编程能力著称。在Ruby开发中,为了管理不同版本的Ruby环境,我们常常会使用到`rbenv`和`ruby-build`这两个工具。本文将详细介绍如何使用`ruby-build...
Ruby是一种简洁而功能强大的编程语言,由日本的松本行弘(Yukihiro "Matz" Matsumoto)在1993年开发,并于1995年公开发布。Ruby语言设计之初就非常注重开发人员的编程体验,它拥有自然、表达性强的语法,易于阅读和...
《Ruby完全自学手册》是一本完全覆盖Ruby和Ruby on Rails的完全自学手册。《Ruby完全自学手册》的特色是由浅入深、循序渐进,注重理论和实践的结合。虽然定位为入门手册,但是依然涉及许多高级技术和应用,覆盖到的...
Ruby是一种面向对象的编程语言,以其简洁、优雅的语法著称,被广泛应用于Web开发,尤其是与Ruby on Rails框架结合使用。"Ruby新手学习书"和"Rails_4_days"这两个资源是为初学者设计的,旨在帮助他们快速掌握Ruby语言...
使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库使用ruby解析awdb离线库...
在IT行业中,管理和切换Ruby版本是一项常见的任务,特别是在开发环境中,不同的项目可能依赖于不同版本的Ruby。`RVM`(Ruby Version Manager)是解决这一问题的利器,它允许开发者在多个Ruby版本之间轻松切换。本文...
Ruby元编程是编程领域中一个深入且强大的主题,它允许程序员在运行时修改或创建代码,极大地提高了灵活性和代码的动态性。这本书“Ruby元编程第二版”专注于讲解Ruby语言的这一独特特性,旨在帮助开发者更好地理解和...
Ruby是一种面向对象的、动态类型的编程语言,以其简洁、优雅的语法和强大的元编程能力而闻名。本资源“ruby-v3.1.1.zip”包含了Ruby的最新版本3.1.1,这是一个重要的里程碑,因为它引入了新特性、性能优化以及对旧...
### Ruby的手动编译安装与升级方法 #### 引言 Ruby是一种动态、面向对象的脚本语言,常被用于Web开发。对于开发者而言,掌握Ruby的安装与配置至关重要。Ubuntu用户通常会依赖于包管理工具`apt-get`来安装Ruby,...
Ruby是一种强大的、面向对象的脚本编程语言,尤其在Web开发领域中被广泛使用,它以其简洁、优雅的语法和强大的社区支持而受到开发者们的喜爱。在Windows操作系统上安装Ruby,有时可能会遇到下载镜像困难的问题,这...
Ruby是一种面向对象的、动态类型的编程语言,以其简洁、优雅的语法和强大的元编程能力而闻名。本教程针对初学者,旨在帮助读者快速掌握Ruby的基础知识,并通过实例深入理解其用法。 首先,Ruby的基本语法是它的一大...
Ruby是一种面向对象的脚本语言,它以其简洁、优雅的语法和强大的元编程能力而闻名。在Ruby-3.0.3软件下载中,我们获得了该语言的最新稳定版本,适用于两种不同的体系结构:64位(x64)和32位(x86)。这使得无论是在...
Ruby是一种面向对象的、动态类型的编程语言,由日本开发者松本行弘于1995年设计并开发。Ruby以其简洁、优雅的语法和强大的元编程能力受到许多开发者的喜爱,尤其在Web开发领域,Ruby on Rails框架的出现极大地推动了...
Ruby是一种强大的动态编程语言,广泛应用于Web开发,脚本编写,服务器管理等领域。为了在没有外网连接的环境中搭建Ruby环境,你需要提前下载并准备相关的安装包。在提供的压缩包中,包含了三个关键文件:`ruby-2.7.2...
Ruby Runtime 插件是 Jenkins 平台上的一款重要组件,它主要为 Jenkins 提供了对 Ruby 运行环境的支持。在 Jenkins 集成环境中,如果你的持续集成或持续部署流程中涉及 Ruby 语言的项目,比如 Rails 应用,那么这款...
Ruby是一种面向对象、动态类型的脚本语言,由Yukihiro "Matz" Matsumoto于1995年创建。它以其简洁、优雅的语法和强大的编程能力而闻名,广泛应用于Web开发、脚本自动化、服务器管理等领域。RubyInstaller是Windows...
《Ruby基础教程(第5版)》是一本由日本知名编程专家高桥征义和后藤裕藏共同著作,经过Ruby之父松本行弘审校的编程入门指南。本书专注于教授Ruby 2.3版本的语法和核心概念,旨在帮助初学者轻松掌握这门强大的面向...
ruby interpreter 原理探討 At first glance, learning how to use Ruby can seem fairly simple. Developers around the world find Ruby’s syntax to be graceful and straightforward. You can express ...
Ruby是一种强大的、面向对象的脚本语言,广泛用于Web开发、服务器端编程和各种应用程序。在Ruby的世界里,管理不同的Ruby实现(如MRI、JRuby、Rubinius、MagLev和MRuby)是非常重要的,这有助于开发者根据项目需求...