Rails 3 Active Record relation order: use a hash instead of a string

To sort a relation in Rails 3, we need to do this:

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

But I think the following:

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

it will be better to understand, because the way the name of the escaped field will be escaped must depend on the adapter ( SqlLite vs Mysql vs PostgreSQL ), right?

Is there something similar to this?

+4
source share
3 answers

As far as I know, there is no way for this syntax built into ActiveRecord, but you can easily add it. I found the order method defined in lib/active_record/relation/query_methods.rb . Theoretically, you should do something like this:

 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 
+2
source

I think the key problem is that the ActiveRecord API is not aware of the ordering semantics . It just takes a string and bypasses the underlying database. Fortunately, Sqlite, MySQL, and PostgreSQL have no difference in order syntax.

I do not think that ActiveRecord can do this abstraction well, and it does not need to be done. It works well with relationship databases, but it is difficult to integrate with NoSQL, for example. MongoDB.

DataMapper , another well-known Ruby ORM, made a better abstraction. Take a look at the query syntax :

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

The API knows about the semantics of ordering. By default, DataMapper will generate an SQL order statement:

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 

However, an override at the DB adapter level is possible:

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:

  • You do not need to worry about the syntax problem if you use only SqlLite, Mysql and PostgreSQL.
  • For a better abstraction, you can try DataMapper.
+2
source

In this particular case, you can clear the “ASC” bit, as the ordering in the entire database implicitly increases

 Foo.order(:bar) 

I know that this does not apply to the case when you want to make order by bar desc , but in fact it does not really matter for the order if you do not use the functions for the offer by offer, in which case there may be something for example squeel will help

0
source

Source: https://habr.com/ru/post/1381317/


All Articles