Rails 3 Active Record关系顺序:使用hash而不是string

要在Rails 3中对关系进行排序,我们必须这样做:

User.where(:activated => true).order('id ASC') 

但我认为这个:

 User.where(:activated => true).order(:id => :asc) 

会有更好的意义,因为字段名称的转义方式应该取决于适配器( SqlLite vs Mysql vs PostgreSQL ),对吧?

有类似的东西吗?

据我所知,ActiveRecord中没有内置这种语法的选项,但是添加一个语句应该不难。 我找到了lib/active_record/relation/query_methods.rb定义的order方法。 从理论上讲,你应该能够做到这样的事情:

 module ActiveRecord module QueryMethods def order(*args) args.map! do |arg| if arg.is_a? Hash # Format a string out of the hash that matches the original AR style stringed_arg else arg end end super end end end 

我认为关键问题是: ActiveRecord API不知道排序语义 。 它只接受一个字符串并绕过底层数据库。 幸运的是,Sqlite,MySQL和PostgreSQL在order语法上没有区别。

我不认为ActiveRecord可以很好地完成这种抽象,并且它不需要这样做。 它适用于关系数据库,但很难与NoSQL集成,例如。 MongoDB的。

另一个着名的Ruby ORM DataMapper做了更好的抽象。 看看它的查询语法 :

 @zoos_by_tiger_count = Zoo.all(:order => [ :tiger_count.desc ]) 

API知道排序语义。 默认情况下,DataMapper将生成SQL顺序语句:

https://github.com/datamapper/dm-do-adapter/blob/master/lib/dm-do-adapter/adapter.rb#L626-634

 def order_statement(order, qualify) statements = order.map do |direction| statement = property_to_column_name(direction.target, qualify) statement << ' DESC' if direction.operator == :desc statement end statements.join(', ') end 

但是,可以在数据库适配器层覆盖:

https://github.com/solnic/dm-mongo-adapter/blob/master/lib/dm-mongo-adapter/query.rb#L260-264

 def sort_statement(conditions) conditions.inject([]) do |sort_arr, condition| sort_arr << [condition.target.field, condition.operator == :asc ? 'ascending' : 'descending'] end end 

TL; DR:

  • 如果您只使用SqlLite,Mysql和PostgreSQL,则无需担心语法问题。
  • 为了更好的抽象,您可以尝试使用DataMapper。

对于这种特殊情况,您可以删除“ASC”位,因为所有数据库中的排序都是隐式升序

 Foo.order(:bar) 

我知道这不包括你想要order by bar desc进行订购的情况,但实际上对于订单来说这并不重要,除非你使用order by子句的函数,在这种情况下可能会像squeel一样有助于