Peter Duijnstee
Peter Duijnstee

Reputation: 3779

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.

Upvotes: 7

Views: 1938

Answers (3)

Peter Duijnstee
Peter Duijnstee

Reputation: 3779

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 ;)

Upvotes: 7

Baylor Rae'
Baylor Rae'

Reputation: 4010

Note: I'm not familiar with DataMapper and my answer might not be within the standards and recommendations of using DataMapper, but it should hopefully give you the result you're looking for.


I've been looking through various Google searches and the DataMapper documentation and I haven't found a way to "order by assocation attribute". The only solution I have thought of is "raw" SQL.

The query would look like this.

SELECT vehicles.* FROM vehicles
LEFT JOIN users ON vehicles.user_id = users.id
ORDER BY users.name

Unfortunately, from my understanding, when you directly query the database you won't get the Vehicle object, but the data from the database.

From the documentation: http://datamapper.org/docs/find.html. It's near the bottom titled "Talking directly to your data-store"

Note that this will not return Zoo objects, rather the raw data straight from the database

Upvotes: 1

Marlin Pierce
Marlin Pierce

Reputation: 10089

Vehicle.joins(:user).order('users.name').all

or in Rails 2.3,

Vehicle.all(:joins => "inner join users on vehicles.user_id = user.id", :order => 'users.name')

Upvotes: -3

Related Questions