Active Record Query Interface(in Rails3)

[url][b]http://guides.rails.info/active_record_querying.html[/b][/url]
[size=medium][color=red][b]1 Retrieving Objects from the Database[/b][/color][/size]
[color=red][b]1.1 Retrieving a Single Object[/b][/color]
[b]使用主键[/b]

[b]Model.find(primary_key)[/b]
如果找不到记录,会raise一个ActiveRecord::RecordNotFound的异常。
[b]first[/b]
Model.first会返回第1条记录。如果表是空的,则返回nil。
[b]last[/b]
Model.last返回最后1条记录。如果表是空的,则返回nil。
[color=red][b]1.2 Retrieving Multiple Objects[/b][/color]
[b]Model.find(1,2)#或者Model.find([1,2])[/b]
如果参数中的任何一个id没有在数据库中找到,会raise一个ActiveRecord::RecordNotFound异常。

[b]Model.each[/b]
有时候也许你会需要遍历一个巨大的记录集,比如发送一个newsletter给每个user,下面的代码是一种很直接的方式:
# 当users表有成千上万条记录的时候,性能会变得非常低下。
User.each do |user| #在Rails2中通常这么使用:User.all.each do |user|
NewsLetter.weekly_deliver(user)
end

在调用each方法的时候,整个users表的数据都会被载入内存。如果用户总数是一个非常大的数字,将会因为内存被占用过多而导致性能低下。

[b]Model.find_each[/b]
为了改善遍历大表的性能,ActiveRecord提供了一个find_each方法:
User.find_each do |user| 
NewsLetter.weekly_deliver(user)
end

find_each默认每次加载1000条数据,然后逐个处理。它接受一个:batch_size选项,可以用来设置每一批数据的数量:
User.find_each(:batch_size => 5000) do |user| 
NewsLetter.weekly_deliver(user)
end

find_each以id的升序来加载对象,id必须是个整数([color=green]其它类型的怎么办?比如uuid[/color])。它还接受一个:start选项,用于设置要加载的对象的id的起始值,下面的代码从id为2000的user开始发送newsletter:
User.find_each(:batch_size => 5000, :start => 2000) do |user| 
NewsLetter.weekly_deliver(user)
end


[b]Model.find_in_batches[/b]
find_each在批量加载指定数量的对象后,依次对每个对象进行处理。find_in_batches和find_each的行为差不多,区别在于加载指定数量的对象后,find_in_batches的block里的参数是一个对象数组,而不是单个对象。

[size=medium][color=red][b]2 Conditions[/b][/color][/size]
Rails3中不再推荐使用Rails2中的那一系列options:
[b]以下引自:[url]http://m.onkey.org/2010/1/22/active-record-query-interface[/url][/b]
[quote]In short, passing options hash containing :conditions, :include, :joins, :limit, : offset, : order, :select, :readonly, :group, :having, :from, :lock to any of the ActiveRecord provided class methods, is now deprecated.

[color=red]简单的说,把:conditions, :include, :joins, :limit, : offset, : order, :select, :readonly, :group, :having, :from, :lock这些选项hash传递给ActiveRecord的任何一个类方法的做法已经不建议使用了。[/color]

Going into details, currently ActiveRecord provides the following finder methods :

[color=red]详细点说,当前版本的ActiveRecord提供了以下finder方法:[/color]

* find(id_or_array_of_ids, options)
* find(:first, options)
* find(:all, options)
* first(options)
* all(options)
* update_all(updates, conditions, options)

And the following calculation methods :

[color=red]和以下统计方法:[/color]

* count(column, options)
* average(column, options)
* minimum(column, options)
* maximum(column, options)
* sum(column, options)
* calculate(operation, column, options)

Starting with Rails 3, [b]supplying any option to the methods above will be deprecated.[/b] Support for supplying options will be removed from Rails 3.2. Moreover, find(:first) and find(:all) ( without any options ) are also being deprecated in favour of first and all. A tiny little exception here is that count() will still accept a :distinct option.

[color=red]从Rails3开始,不建议给以上的方法传递任何选项,并且[b]将在Rails3.2中移除对这种方式的支持[/b]。同时,find(:first)和find(:all)(不带任何其它选项)也不建议使用,而改用first、all方法。但是还有个特例:count()方法将仍然接收:distinct选项。[/color][/quote]

那Rails3 中要如何按条件查询、如何给查询结果排序呢?
[color=red][b]2.1 Pure String Conditions[/b][/color]

[b]Model.where()[/b]

Rails3给Model提供了一个where方法,参数可以是一个简单的字符串,当它的参数只是一个简单的字符串的时候,这个参数将被拼接在生成的SQL语句的“WHERE”之后。Client.where("orders_count = '2'")将会返回所有orders_count字段为2的client。但这种方式极不安全,容易受到SQL注入攻击。

[color=red][b]2.2 Array Conditions[/b][/color]

安全的办法是使用数组形式的参数:
Client.where(["orders_count = ?", params[:orders]])

如果你要指定两个条件,可以这样:
Client.where(["orders_count = ? AND locked = ?", params[:orders], false]) 

数组中第一个元素和原来的查询条件差不多,只是把值都换成了问号。接下来的元素每一个都依次和第一个元素字符串中的问号对应。

[color=red][b]2.2.1 Placeholder Conditions[/b][/color]
另一种方法和上面的差不多,只是数组只有2个元素:
Client.where(  ["created_at >= :start_date AND created_at <= :end_date", { :start_date => params[:start_date], :end_date => params[:end_date] }])

这里把前面的问号占位符换成了以冒号开头的字符串(这里不能说是symbol吧?),分别对应第2元素中的key。第2个元素是个hash,它的值将被用于替换第一个元素中的占位符(就是以冒号开头的字符串)。

[color=red][b]2.2.2 Range Conditions[/b][/color]
数组的第2个元素还可以是一个Range对象,经常和“IN”搭配使用,如:
Client.where(["created_at IN (?)", (params[:start_date].to_date)..(params[:end_date].to_date)])

如果这个Range是个小范围,生成的查询一般不会有什么问题。但如果是个大范围,比如一年的365天,生成的SQL将会是这样:
SELECT * FROM users WHERE (created_at IN ('2007-12-31','2008-01-01','2008-01-02','2008-01-03','2008-01-04','2008-01-05', '2008-01-06','2008-01-07','2008-01-08','2008-01-09','2008-01-10','2008-01-11', '2008-01-12','2008-01-13','2008-01-14','2008-01-15','2008-01-16','2008-01-17', '2008-01-18','2008-01-19','2008-01-20','2008-01-21','2008-01-22','2008-01-23',... ‘2008-12-15','2008-12-16','2008-12-17','2008-12-18','2008-12-19','2008-12-20', '2008-12-21','2008-12-22','2008-12-23','2008-12-24','2008-12-25','2008-12-26', '2008-12-27','2008-12-28','2008-12-29','2008-12-30','2008-12-31'))

[color=red][b]2.2.3 Time and Date Conditions[/b][/color]
上面那种情况可能会引发一个SQL服务器的异常,例如MySQL会抛出这样一个异常:[quote]Got a packet bigger than 'max_allowed_packet' bytes: _query_ [/quote]
比较好的办法是使用之前的Array Conditions或者Placeholder Conditions:
Client.where(  ["created_at > ? AND created_at < ?", params[:start_date], params[:end_date]])


[color=red][b]2.3 Hash Conditions[/b][/color]

除了字符串、数组,where()方法还支持Hash形式的条件。
[color=red][b]2.3.1 Equality Conditions[/b][/color]
Client.where({ :locked => true })
#或者
Client.where({ 'locked' => true })

[color=red][b]2.3.2 Range Conditions[/b][/color]
Client.where({ :created_at => (Time.now.midnight - 1.day)..Time.now.midnight}) 

将会生成SQL语句:
SELECT * FROM clients WHERE (clients.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')

[color=red][b]2.3.3 Subset Conditions[/b][/color]
Client.where({ :orders_count => [1,3,5] }) 

将生成SQL语句:
SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5)) 

[color=red][b]2.4 Ordering[/b][/color]
Rails3提供了一个[b]order()[/b]方法用于排序。
Client.order("created_at") 
Client.order("created_at DESC")
#或
Client.order("created_at ASC")
#还可以根据多个字段来排序:
Client.order("orders_count ASC, created_at DESC")

………………不记了,也就是把那些个options换成了对应的方法。然后,由于这些方法[b]返回的是一个ActiveRecord::Relation的对象,并且数据不是即时加载的[/b],所以这些方法可以[b]链式调用[/b]例如:
User.order('users.id DESC').limit(20).includes(:items)

甚至可以这样:
cars = Car.where(:colour => 'black')
rich_ppls_cars = cars.order('cars.price DESC').limit(10)

(感觉好像SearchLogic)
还有,joins()方法只支持内联接(INNER JOIN)。Rails2的named_scope被改名为scope,还有新增的scoped、with_scope和with_exclusive_scope方法,更多更详细的新特性可以参考:[url]http://m.onkey.org/2010/1/22/active-record-query-interface[/url]

[url]http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/[/url]这篇博客让我想起一个[url="http://www.iteye.com/news/12993"]JavaEye新闻[/url],找了一下,果然就是这篇,因为当时rails3还没有发布,所以没有太在意。

[color=red][b]Validations[/b][/color]
[url]http://guides.rails.info/3_0_release_notes.html#validations[/url]
[quote]Validations have been moved from Active Record into Active Model, providing an interface to validations that works across ORM libraries in Rails 3.

* There is now a validates :attribute, options_hash shortcut method that allows you to pass options for all the validates class methods, you can pass more than one option to a validate method.
* The validates method has the following options:
* :acceptance => Boolean.
* :confirmation => Boolean.
* :exclusion => { :in => Ennumerable }.
* :inclusion => { :in => Ennumerable }.
* :format => { :with => Regexp, : on => :create }.
* :length => { :maximum => Fixnum }.
* :numericality => Boolean.
* :presence => Boolean.
* :uniqueness => Boolean.
[color=red]All the Rails version 2.3 style validation methods are still supported in Rails 3.0, [b]the new validates method is designed as an additional aid in your model validations, not a replacement for the existing API[/b].[/color][/quote]

============算了,直接在这汇总一下吧:=============

Rails3中,[b]路由[/b]的写法变了,可以参考:
[url]http://guides.rails.info/routing.html[/url]
[url]http://rizwanreza.com/2009/12/20/revamped-routes-in-rails-3[/url]
还有routes.rb的注释部分。

[b]不再使用script/server这样的方式运行rails程序[/b],而改用rails server命令。原来的一系列script/xxxx脚本全没了,统一使用rails命令。
rails generate controller home index
上面那句甚至可以这样写:
rails g controller home index

[b]migration的写法似乎没有变化。[/b]

在之前的Rails中,经常需要在页面中调用[b]h方法[/b],像这样:
<%= h post.name %>
来防止html注入。在Rails3中不需要这么做了,转义的动作变成默认的,如果需要取消转义,只要调用[b]raw方法[/b]即可:
<%= raw post.name %>

最后,还有一处大改动,就是[b]JavaScript的Helper[/b],这个可以参考比较早的一个帖子:[url]http://www.iteye.com/topic/476671[/url]
一个老外的[url="http://zaa.ch/24"]Unobtrusive JavaScript in Rails3[/url]
这里有一篇比较详细的JavaScript in Rails3:[url]http://cn.asciicasts.com/episodes/205-unobtrusive-javascript[/url]

两个链接:[url="http://liuming.iteye.com/blog/578339"]Rails 3 文章集合[/url]、[url="http://www.iteye.com/topic/591833"]Rails3 Beta 发布: 重点导览[/url]

补一个infoQ关于Rails3的报道:[url]http://www.infoq.com/cn/news/2010/02/rails-3-beta[/url]

[b]再补一篇夜鸣猪的译文:[url="http://hlee.iteye.com/blog/603831"]Rails 3中的Active Record的查询变化[/url],比我这个详细。[/b]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值