`

Active Record Query Interface(in Rails3)

 
阅读更多

来自:http://www.cnblogs.com/lexus/archive/2010/11/11/1875134.html

http://guides.rails.info/active_record_querying.html  
1 Retrieving Objects from the Database  
1.1 Retrieving a Single Object  
使用主键  

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

Model.each  
有时候也许你会需要遍历一个巨大的记录集,比如发送一个newsletter给每个user,下面的代码是一种很直接的方式:

Ruby代码 
  1. # 当users表有成千上万条记录的时候,性能会变得非常低下。   
  2. User.each   do  |user|  #在Rails2中通常这么使用:User.all.each do |user|   
  3.   NewsLetter.weekly_deliver(user)   
  4. end    


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

Model.find_each  
为了改善遍历大表的性能,ActiveRecord提供了一个find_each方法:

Ruby代码 
  1. User.find_each  do  |user|   
  2.   NewsLetter.weekly_deliver(user)   
  3. end    


find_each默认每次加载1000条数据,然后逐个处理。它接受一个:batch_size选项,可以用来设置每一批数据的数量:

Ruby代码 
  1. User.find_each( :batch_size  => 5000)  do  |user|   
  2.   NewsLetter.weekly_deliver(user)   
  3. end    


find_each以id的升序来加载对象,id必须是个整数(其它类型的怎么办?比如uuid )。它还接受一个:start选项,用于设置要加载的对象的id的起始值,下面的代码从id为2000的user开始发送newsletter:

Ruby代码 
  1. User.find_each( :batch_size  => 5000,  :start  => 2000)  do  |user|   
  2.   NewsLetter.weekly_deliver(user)   
  3. end    



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

2 Conditions  
Rails3中不再推荐使用Rails2中的那一系列options: 
以下引自:http://m.onkey.org/2010/1/22/active-record-query-interface

引用
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. 

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

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

详细点说,当前版本的ActiveRecord提供了以下finder方法:  

    * 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 : 

和以下统计方法:  

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

Starting with Rails 3, supplying any option to the methods above will be deprecated.  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. 

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



那Rails3 中要如何按条件查询、如何给查询结果排序呢? 
2.1 Pure String Conditions  

Model.where()  

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

2.2 Array Conditions  

安全的办法是使用数组形式的参数:

Ruby代码 
  1. Client.where([ "orders_count = ?" , params[ :orders ]])  


如果你要指定两个条件,可以这样:

Ruby代码 
  1. Client.where([ "orders_count = ? AND locked = ?" , params[ :orders ],  false ])   


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

2.2.1 Placeholder Conditions  
另一种方法和上面的差不多,只是数组只有2个元素:

Ruby代码 
  1. 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,它的值将被用于替换第一个元素中的占位符(就是以冒号开头的字符串)。 

2.2.2 Range Conditions  
数组的第2个元素还可以是一个Range对象,经常和“IN”搭配使用,如:

Ruby代码 
  1. Client.where([ "created_at IN (?)" , (params[ :start_date ].to_date)..(params[ :end_date ].to_date)])  


如果这个Range是个小范围,生成的查询一般不会有什么问题。但如果是个大范围,比如一年的365天,生成的SQL将会是这样:

Sql代码 
  1. 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'))  


2.2.3 Time and Date Conditions  
上面那种情况可能会引发一个SQL服务器的异常,例如MySQL会抛出这样一个异常:

引用
Got a packet bigger than 'max_allowed_packet' bytes: _query_


比较好的办法是使用之前的Array Conditions或者Placeholder Conditions:

Ruby代码 
  1. Client.where(  [ "created_at > ? AND created_at < ?" , params[ :start_date ], params[ :end_date ]])  



2.3 Hash Conditions  

除了字符串、数组,where()方法还支持Hash形式的条件。 
2.3.1 Equality Conditions

Ruby代码 
  1. Client.where({  :locked  =>  true  })  
  2. #或者   
  3. Client.where({ 'locked'  =>  true  })   


2.3.2 Range Conditions

Ruby代码 
  1. Client.where({  :created_at  => ( Time .now.midnight - 1.day).. Time .now.midnight})   


将会生成SQL语句:

Sql代码 
  1. SELECT  *  FROM  clients  WHERE  (clients.created_at  BETWEEN   '2008-12-21 00:00:00'   AND   '2008-12-22 00:00:00' )  


2.3.3 Subset Conditions

Ruby代码 
  1. Client.where({  :orders_count  => [1,3,5] })   


将生成SQL语句:

Sql代码 
  1. SELECT  *  FROM  clients  WHERE  (clients.orders_count  IN  (1,3,5))   


2.4 Ordering  
Rails3提供了一个order() 方法用于排序。

Ruby代码 
  1. Client.order( "created_at" )   
  2. Client.order("created_at DESC" )   
  3. #或    
  4. Client.order("created_at ASC" )   
  5. #还可以根据多个字段来排序:   
  6. Client.order("orders_count ASC, created_at DESC" )   


………………不记了,也就是把那些个options换成了对应的方法。然后,由于这些方法返回的是一个ActiveRecord::Relation的对象,并且数据不是即时加载的 ,所以这些方法可以链式调用 例如:

Ruby代码 
  1. User.order( 'users.id DESC' ).limit(20).includes( :items )  


甚至可以这样:

Ruby代码 
  1. cars = Car.where( :colour  =>  'black' )  
  2. rich_ppls_cars = cars.order('cars.price DESC' ).limit(10)  


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

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

Validations  
http://guides.rails.info/3_0_release_notes.html#validations

引用
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. 
All the Rails version 2.3 style validation methods are still supported in Rails 3.0, the new validates method is designed as an additional aid in your model validations, not a replacement for the existing API .



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

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

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

migration的写法似乎没有变化。  

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

分享到:
评论

相关推荐

    Pro Active Record. Databases with Ruby and Rails

    Databases with Ruby and Rails》是一本深入探讨Ruby on Rails框架中Active Record库的专著。这本书详细阐述了如何利用Ruby语言和Rails框架来高效地处理数据库操作,帮助开发者理解并掌握数据库与Web应用之间的紧密...

    active_record_upsert, Rails 5/Active Record 5的更新更新.zip

    active_record_upsert, Rails 5/Active Record 5的更新更新 ActiveRecordUpsertpostgre 9.5 和 Rails 5/ActiveRecord 5的真正更新。 在冲突时使用进行更新。的主要点是否在单个记录上使用 ON CONFLICT DO U

    Rails 3中的Active Record的查询变化.doc

    在Rails 3中,Active Record查询接口发生了显著的变化,这些变化主要是为了提高代码的可读性和性能,引入了懒加载(Lazy Loading)的概念。本文将详细介绍这些查询方式的转变及其背后的动机。 首先,我们注意到旧版...

    Rails 4 in Action, Second Edition.pdf

    - **Active Record Query Interface**:Rails 4在Active Record中引入了一个新的查询接口,使数据库操作更加直观和高效。 - **Secure Cookies**:为了提高安全性,Rails 4引入了一种新的安全cookie机制,可以更好地...

    Pro.Active.Record.Databases.with.Ruby.and.Rails

    ### Pro Active Record Databases with Ruby and Rails #### 概述 《Pro Active Record Databases with Ruby and Rails》一书由Kevin Marshall、Chad Pytel和Jon Yurek共同撰写,旨在帮助开发者掌握如何使用Ruby及...

    Ruby on Rails Guides_ A Guide to Active Record Associations.pdf

    Ruby on Rails Guides_ A Guide to Active Record Associations.pdf

    active_record_upsert:Rails的Upsert 5 Active Record 5

    ActiveRecordUpsert PostgreSQL 9.5+和Rails 5+ / ActiveRecord 5+的真实更新。 使用 。 要点 使用ON CONFLICT DO UPDATE在单个记录... gem 'active_record_upsert' 然后执行: $ bundle 或将其自己安装为: $ gem

    种使用MVC架构开发的Trello,使用Active Record进行数据库查询.zip

    Active Record是Ruby on Rails框架中的一个核心组件,它将数据库操作封装在对象中,使得数据库访问变得简单而直观。在MVC架构中,Active Record作为模型层的一部分,负责与数据库进行交互。 1. **数据库映射**: ...

    Rails 3 in Action

    《Rails 3 in Action》是2011年由Ryan Bigg撰写的一本关于Ruby on Rails框架的权威指南,专门针对当时最新的Rails 3.1版本进行了深入解析。这本书旨在帮助开发者充分利用Rails 3.1的强大功能,提升Web应用开发的效率...

    好用的rails 2.0 Api 文档

    Rails 2.0提供了ActiveRecord查询接口(Query Interface),允许开发者编写复杂的数据库查询。包括find、where、all、exists?等方法,可以进行条件筛选、分组、联接、排序等操作。 **8. Plugins和Gemfile** Rails ...

    rails4.0.0

    2. **查询接口(Query Interface)** 这个版本加强了查询接口,引入了`exists?`方法,可以用来检查是否存在特定的记录,而不会加载整个对象。此外,`pluck`方法允许开发者直接从数据库中抽取指定列的数据,无需创建...

    Rails相关电子书汇总二

    标题中的“Rails相关电子书汇总二”表明这是一个关于Ruby on Rails框架的电子书籍集合,特别是与Active Record数据库交互相关的主题。Rails是Ruby编程语言的一个流行Web应用框架,它以其MVC(模型-视图-控制器)架构...

    Active Record所引用的程序集

    Active Record是Ruby on Rails框架中的一个核心组件,它实现了对象关系映射(ORM)系统,使得开发者能够以面向对象的方式处理数据库操作。在.NET环境中,虽然没有原生的Active Record库,但存在类似的概念和库,如...

    active-record-query-trace:记录日志的Rails插件显示Active Record执行的所有SQL查询的回溯

    在Rails的开发控制台和日志中显示每个查询的回溯。 允许您跟踪应用程序中查询的执行位置。 对于性能优化以及在对大型应用程序进行更改时查找从哪里开始有用。 启用后,每个查询都会记录如下: D, [2019-03-03T19:...

    activerecord-session_store:从Rails中提取的Active Record的会话存储

    rails generate active_record:session_migration 运行迁移: rake db:migrate 然后,在config/initializers/session_store.rb设置会话存储: Rails . application . config . session_store :active_record_...

    rails2.3.2

    1. Active Record:这是 Rails 的 ORM(对象关系映射)层,负责处理数据库交互。在这一版本中,Active Record 提供了更强大的查询接口,包括 SQL 方法的集成和更灵活的关系管理。 2. Action Pack:包含了 MVC 架构...

    Beginning Rails 3

    - **Active Record**:Rails 3 使用 Active Record 模式来处理数据库交互,提供了一种声明式的接口来操作数据库记录。 - **关联关系**:支持多种关联关系,如一对一、一对多、多对多等,使得数据模型之间的关系更加...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    通过以上介绍,我们不仅了解了Rails的基础知识,还深入探讨了其核心组件——Active Record的相关概念和技术细节。这些内容对于初学者来说是非常宝贵的入门资料,同时也是进一步学习和实践的基石。随着对Rails的深入...

Global site tag (gtag.js) - Google Analytics