• activerecord查询语法for rails3


    Rails3的ActiveRecord 查询API

    jerry 分享于 about 1 month 前, 3 条回复208 次浏览

    Rails3ActiveRecord中修改了较多的代码,很多以前Rails2中普遍使用的用法在Rails3中已经不推荐使用或者已经被移除, 所以此文让大家知道如何去写好Rails3的代码。 本文是翻译自Pratik Naik博客的一篇文章。

    众所周知,很多rails2的active record查询方法在rails3众已经不推荐使用,也就是说,过时了。那么,哪些写法在rails3.1众已经不推荐使用了呢?

    这些不推荐使用的写法在rails3.1 release版中依然有效,但是将会在rails3.2中全面的移除,考虑到牵涉了比较多的代码修改,所以将会有一个官方的插件来支持他们。

    简而言之,通过包含hash的任何ActiveRecord的类方法,都已经不推荐了,比如:

    :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from, :lock  

    目前ActiveRecord提供了以下finder方法:

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

    还有以下的计算方法:

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

    进入rails3的世界,以上的方法都是不推荐使用的。这些方法将会在rails3.2中完整的移除。此外,find(:first) , find(:all) 也已经不推荐使用了,小小的例外是 count()方法依然接受 :distinct 参数。

    下面是一些在 rails3中过时用法的例子:

    User.find(:all, :limit => 1)
    User.find(:all)
    User.find(:first)
    User.first(:conditions => {:name => 'lifo'})
    User.all(:joins => :items)  

    但是以下的用法还是推荐使用的:

    User.find(1)
    User.find(1,2,3)
    User.find_by_name('lifo')  

    此外,在rails2中使用率相当大的named_scope 也已经不推荐了

    named_scope :red, :conditions => { :colour => 'red' }
    named_scope :red, lambda {|colour| {:conditions => { :colour => colour }} }  

    with_scope, with_exclusive_scope 和 default_scope 也不推荐使用。

    with_scope(:find => {:conditions => {:name => 'lifo'}) { ... }
    with_exclusive_scope(:find => {:limit =>1}) { ... }
    default_scope :order => "id DESC"  

    动态 scoped_by_ 也将会废弃。

    red_items = Item.scoped_by_colour('red')
    red_old_items = Item.scoped_by_colour_and_age('red', 2)

    新的API

    Rails3的 ActiveRecord 有以下的finder方法:

    • where (:conditions)
    • having (:conditions)
    • select
    • group
    • order
    • limit
    • offset
    • joins
    • includes (:include)
    • lock
    • readonly
    • from

    Chainability

    上述的方法都会返回一个关系,从概念上讲,这种关系其实都是一个 named scope类型。所有的这些方法都很好的在关系对象中定义了。

    lifo = User.where(:name => 'lifo')
    new_users = User.order('users.id DESC').limit(20).includes(:items)  

    你可以在现有的关系中应用更多的finder方法

    cars = Car.where(:colour => 'black')
    rich_ppls_cars = cars.order('cars.price DESC').limit(10)

    Quacks like a Model

    Quacks relation 在涉及到主要的CRUD方法的时候其实就像一个模型,你可以调用以下任何方法。

    • new(attributes)
    • create(attributes)
    • create!(attributes)
    • find(id_or_array)
    • destroy(id_or_array)
    • destroy_all
    • delete(id_or_array)
    • delete_all
    • update(ids, updates)
    • update_all(updates)
    • exists?

    那么,下面的代码是我们所希望看到的:

    red_items = Item.where(:colour => 'red')
    red_items.find(1)
    item = red_items.new
    item.colour #=> 'red'
    
    red_items.exists? #=> true
    red_items.update_all :colour => 'black'
    red_items.exists? #=> false  

    请注意,调用任何的CRUD方法将会重置关系,也就是说,将会删除记录的缓存,例如 relation.size。

    Lazy Loading 延迟加载

    我们可能会从上面的例子清楚的知道,关系是延迟加载的,也就是调用了一个枚举的方法,这和 associations 和 named_scopes 是如何协作的比较相似。

    cars = Car.where(:colour => 'black') # No Query
    cars.each {|c| puts c.name } # Fires "select * from cars where ..."  

    这是非常有用的片段缓存,在你的controller,可以这么写

    def index
      @recent_items = Item.limit(10).order('created_at DESC')
    end  

    然后在你的view中这么写

    <% cache('recent_items') do %>
      <% @recent_items.each do |item| %>
        ...
      <% end %>
    <% end %>

    在上述例子中,@recent_items 在视图中调用了@recent_items.each后才被加载,作为控制器实际上并没有触发任何查询,在不需要任何特殊工作的时候,片段缓存变得非常有效。

    Force loading – all, first & last

    有时候,你可能不需要延迟加载,那么,你可以强制进行加载。

    cars = Car.where(:colour => 'black').all  

    需要注意的是.all后返回的是一个数组,而不是一个关系。这和rails 2.3下 named_scopes and associations是相类似的。

    同样,first 和last 总是会返回一个 ActiveRecord对象或者nil.

    cars = Car.order('created_at ASC')
    oldest_car = cars.first
    newest_car = cars.last  

    named_scope -> scopes

    named_scope在Rails3.0中已经不推荐使用了,你只要将 “named_”这部分去掉就可以了。也就是说 named_scope已经被重新命名成scope了。

    老的写法是:

    class Item
      named_scope :red, :conditions => { :colour => 'red' }
      named_scope :since, lambda {|time| {:conditions => ["created_at > ?", time] }}
    end  

    新的写法是:

    class Item
      scope :red, :conditions => { :colour => 'red' }
      scope :since, lambda {|time| {:conditions => ["created_at > ?", time] }}
    end

    然而,以上使用的conditions的hash将会在Rails3.1中移除,所以我们需要这么写:

    class Item
      scope :red, where(:colour => 'red')
      scope :since, lambda {|time| where("created_at > ?", time) }
    end  

    在内部,命名规范是建立在关系之上的,使它更简单的使用和混用finder方法。

    red_items = Item.red
    available_red_items = red_items.where("quantity > ?", 0)
    old_red_items = Item.red.since(10.days.ago)  

    Model.scoped

    如果你想建立一个复杂的关系查询,从一个空白的关系出发,那么Model.scoped将会是你用到的。

    cars = Car.scoped
    rich_ppls_cars = cars.order('cars.price DESC').limit(10)
    white_cars = cars.where(:colour => 'red')  

    说到内部,ActiveRecord::Base有以下delegations:

    delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
    delegate :select, :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :to => :scoped
    delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped  

    以上的可能会给你一个更好的方向去理解ActiveRecord::Base类内部是如何工作的。包括动态的finder方法,比如 find_by_name. find_all_by_name_and_colour 等。

    with_scope and with_exclusive_scope

    with_scope和with_exclusive_scope 现在已被较好的实施在了关系之上:

    with_scope(where(:name => 'lifo')) do
      ...
    end  

    或者使用一个 named scope:

    with_exclusive_scope(Item.red) do
      ...
    end  

    本文是翻译自Pratik Naik 博客的一篇文章。Active Record Query Interface 3.0

    回复 (3 条)

    添加回复

    1. 如果你还未注册, 请填写你的名字。

    2. 你可以实用以下html标签:

      <a href="" title=""> <b> <blockquote> <pre> <code> <em> <i> <strong>

      代码块请使用 <pre><code>...</code></pre>.

  • 相关阅读:
    Java检测文件是否UTF8编码
    Linux: uid/euid/suid的关系
    位移运算
    Springmvc 重定向参数传递方式
    @RequestBody和@RequestParam区别
    jsp页面老提示Multiple annotations found at this line:
    滚动表格代码
    滚动条样式修改
    WebService的四种客户端调用方式
    table元素的td和ul元素li隔行变色
  • 原文地址:https://www.cnblogs.com/lexus/p/1885489.html
Copyright © 2020-2023  润新知