3

I need to order a query of Profile entries in an ActiveRecord::Relation object by a value that is computed on run-time.

I have created and assigned a temporary column distance in my controller for the Relation object by using attr_accessor like so:

@profiles.each do |p|
  p.class_eval do
   attr_accessor :distance
  end
end

@profiles.each do |p|
  p.distance = distance_arr[@profiles.index(p)]  # Distance values obtained from an instance array
end

However, when I try to order the Relation with the order method, I get a no such column: distance error i.e. it's not picking up the temporary field.

Here's how I tried to order it in my controller (note I'm using the will_paginate gem, but that is irrelevant).

@profiles = @profiles.order('distance ASC').paginate(page: params[:page])
Richard
  • 828
  • 1
  • 8
  • 28

1 Answers1

2

You've added the distance attribute to the profile instances. So the distance stuff is all in ruby and sql doesn't know anything about it. Since you are calculating the distances in ruby you'll need to order them in ruby. You can make use of the sort_by method.

@profiles.sort_by{|p| p.distance}

Alternatively you could push the distance calculation into sql. Something like the following

@profiles = Profile.select('*, 10 as distance').order('distance')

Here you can see the computed distance column has been added to the select which tells active record to change the query.

Joshua
  • 2,079
  • 20
  • 29
  • The sort_by method works perfectly, thanks! On a side note, to get `will_paginate` working with Array objects, I had to add a require statement http://stackoverflow.com/questions/4352895/ruby-on-rails-will-paginate-an-array – Richard Jun 28 '15 at 06:54