Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datamapper: Sorting results through association

I'm working on a Rails 3.2 app that uses Datamapper as its ORM. I'm looking for a way to sort a result set by an attribute of the associated model. Specifically I have the following models:

class Vehicle
  include DataMapper::Resource

  belongs_to :user
end

class User
  include DataMapper::Resource

  has n, :vehicles
end

Now I want to be able to query the vehicles and sort them by the name of the driver. I tried the following but neither seems to work with Datamapper:

> Vehicle.all( :order => 'users.name' )
ArgumentError: +options[:order]+ entry "users.name" does not map to a property in Vehicle

> Vehicle.all( :order => { :users => 'name' } )
ArgumentError: +options[:order]+ entry [:users, "name"] of an unsupported object Array

Right now I'm using Ruby to sort the result set post-query but obviously that's not helping performance any, also it stops me from further chaining on other scopes.

like image 629
Peter Duijnstee Avatar asked Sep 14 '12 17:09

Peter Duijnstee


1 Answers

I spent some more time digging around and finally turned up an old blog which has a solution to this problem. It involves manually building the ordering query in DataMapper.

From: http://rhnh.net/2010/12/01/ordering-by-a-field-in-a-join-model-with-datamapper

def self.ordered_by_vehicle_name direction = :asc
  order = DataMapper::Query::Direction.new(vehicle.name, direction)
  query = all.query
  query.instance_variable_set("@order", [order])
  query.instance_variable_set("@links", [relationships['vehicle'].inverse])
  all(query)
end

This will let you order by association and still chain on other scopes, e.g.:

User.ordered_by_vehicle_name(:desc).all( :name => 'foo' )

It's a bit hacky but it does what I wanted it to do at least ;)

like image 89
Peter Duijnstee Avatar answered Sep 30 '22 23:09

Peter Duijnstee