Rails improves the "in_order_of" querying method


Rails ActiveRecord is continuously being improved. The latest improvement is the “in_order_of” method. This method is used to order records in the order of the given values (of a particular column). This query previously only used to allow symbolic column names, it now handles string values also.

Before

Let’s create a Rocket model which has id and name attributes. Now, when trying to order the records in the order of the given values, we can use the “in_order_of” method as shown below.

  irb(main):012:0> Rocket.in_order_of(:id, [1,2,3]).count
    Rocket Count (1.1ms)  SELECT COUNT(*) FROM "rockets" WHERE "rockets"."id" IN (1, 2, 3)
  => 3

However if we try to use the “in_order_of” method with string values, it throws an error.

irb(main):001:0> Rocket.in_order_of('id', [1,2,3]).count
/Users/swaathi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4/lib/active_record/relation/query_methods.rb:459:in `in_order_of': undefined method `in' for "id":String (NoMethodError)                                                                   
                                                                                        
      .where!(arel_column.in(values))                                                  
                          ^^^                                                           
Did you mean?  in?

As you can see, the error is thrown because the “in_order_of” method is trying to call the “in” method on the string value “id”.

After

Thanks to this PR the ActiveRecord queries no longer check if a given column is symbol and then perform a query, but instead check for Arel types. This allows for greater flexibility.

What used to be,

activerecord/lib/active_record/relation/query_methods.rb

  ...
  arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
  ...

is now,

  ...
  arel_column = column.is_a?(Arel::Nodes::SqlLiteral) ? column : order_column(column.to_s)
  ...

Now when we try to use the “in_order_of” method with string values, it works as expected.

  irb(main):001:0> Rocket.in_order_of('id', [1,2,3]).count
    (0.2ms)  SELECT COUNT(*) FROM "rockets" WHERE "rockets"."id" IN (1, 2, 3)
  => 3

Join Our Newsletter