`
friendsys
  • 浏览: 337241 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Rails随记

    博客分类:
  • Ruby
阅读更多
绕了不少弯路,感觉这本书上说的还是比较简单

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" , :object => @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_to :order 后者同上

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 => :orders) }
调用model的to_xml方法

生成指定格式的feed xml格式文件
format.atom { render :layout => false }
生成JSON 的格式,针对http header请求
format.json { render :layout => false ,:json => @product.to_json(:include => :orders) }

生成文档
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_column :orders, :e_mail, :customer_email
修改列属性
change_column :orders, :order_type, :string

重命名表,注意对原有的model代码也会修改
rename_table :order_histories, :order_notes

当添加一些不允许修改的表信息时,可以在self.down中抛出异常,防止错误的修改,导致数据丢失
def self.down
	raise ActiveRecord::IrreversibleMigration
end

对表的创建,注意block的使用
def self.up
create_table :order_histories do |t|
		t.integer :order_id, :null => false
		t.text :notes
		t.timestamps
	end
end

定义索引,这里并不很了解,建议需要时查看API
add_index :orders, :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, :options =>
	"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,
											:order => "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_to :order
B:has_one :invoice

One-to-Many
A:belongs_to :order 	#一方
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,
								:on => :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, :only_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进行设置
session :off, :only => %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的使用
session :off
也可以附带更多参数
session :off, :only => [ :show, :list ]
session :off, :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验证
区别于对于字段属性的验证, 是用于权限验证的机制
verify :only => :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,
							:only => [ :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' ,
			:object => @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" , :object => @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连接






































分享到:
评论
2 楼 zhangyanan_it 2014-07-02  
楼主总结的好多!想问下:
map.resources :roles
:member =>{
    :people => :get
}
形成的path怎么是:people_role_url?
很不解?有没有什么资料是描述这个的?
1 楼 lezi2012 2013-08-01  
感谢分享!!!感谢分享!!!感谢分享!!!感谢分享!!!感谢分享!!!感谢分享!!!感谢分享!!!感谢分享!!!

相关推荐

    rails 2.3.2离线安装rails 2.3.2离线安装

    rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails 2.3.2离线安装rails ...

    [Rails] Crafting Rails Applications (英文版)

    [Pragmatic Bookshelf] Crafting Rails Applications Expert Practices for Everyday Rails Development (E-Book) ☆ 图书概要:☆ Rails 3 is a huge step forward. You can now easily extend the framework, ...

    [Rails] 敏捷网络应用开发 (Rails 4 实现) (英文版)

    Rails 4 introduces a number of user-facing changes, and the ebook has been updated to match all the latest changes and new best practices in Rails. This includes full support for Ruby 2.0, controller ...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    Ruby on Rails Tutorial

    《Ruby on Rails Tutorial》中文版(原书第2版,涵盖 Rails 4) Ruby 是一门很美的计算机语言,其设计原则就是“让编程人员快乐”。David Heinemeier Hansson 就是看重了这一点,才在开发 Rails 框架时选择了 Ruby...

    Rails之道,完整扫描版

    《Rails之道》按照Rails的各个子系统进行组织编排,分别介绍了Rails的环境、初始过程、配置和日志记录,Rails的分配器、控制器、页面生成和路由,REST、资源和Rails,ActiveRecord的基础、关联、验证和高级技巧,...

    Rails项目源代码

    一个用Ruby on Rails搭建的图片分享的网站项目.完整源代码

    rails敏捷开发的购物车系统

    本资源是参照rails敏捷开发第四版书中的例子,rails的版本是rails3.2.6

    Bootstrap for Rails (2015)

    Bootstrap 3 和 Rails 4(样例用的是Ruby 2.1.1,Rails 4.1.4) Table of Contents Preface 1 Chapter 1: Introducing Web Application Development in Rails 7 Why Bootstrap with Rails? 8 Setting up a Todo ...

    adminlte-rails, AdminLTE Rails gem 将AdminLTE主题与 Rails 资产管道集成.zip

    adminlte-rails, AdminLTE Rails gem 将AdminLTE主题与 Rails 资产管道集成 AdminLTE Rails gem AdminLTE 是后端的高级 Bootstrap 主题。英镑 AdminLTE Rails gem 与 Rails 资产管道集成了英镑AdminLTE主题。安装将...

    Agile Web Development with Rails 4

    Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details., Tens of thousands of ...

    提升Ruby on Rails性能的几个解决方案

    Ruby On Rails 框架自它提出之日起就受到广泛关注,在“不要重复自己”,“约定优于配置”等思想的指导下,Rails 带给 Web 开发者的是极高的开发效率。 ActiveRecord 的灵活让你再也不用配置繁琐的 Hibernate 即可...

    [Rails] Rails Devise 学习教程 (英文版)

    [Packt Publishing] Rails Devise 学习教程 (英文版) [Packt Publishing] Learning Devise for Rails (E-Book) ☆ 图书概要:☆ Use Devise to make your Rails application accessible, user friendly, and ...

    使用Aptana+Rails开发Rails Web应用(中文)

    使用Aptana+Rails开发Rails Web应用 有Aptana的安装配置等等,中文

    Rails101_by_rails4.0

    中文世界唯一一本Rails 4.0.0 + Ruby 2.0.0 的自學書籍

    rails api(文档)

    rails文档 rails api 英文

    rails指南 中文版

    rails指南 中文版

    minitest-rails, Rails的Minitest集成.zip

    minitest-rails, Rails的Minitest集成 minitestRails 5的Minitest集成 安装gem install minitest-rails这将安装以下宝石:minitest配置创建一个新的Rail

    Learning Rails 5(高清文字pdf版)

    If you’re a web developer or designer ready to learn Ruby on Rails, this hands-on guide is the ideal way to get started. Rather than toss you into the middle of the framework’s Model-View-Controller...

Global site tag (gtag.js) - Google Analytics