views:

43

answers:

2

I have a Model which has a belongs_to association with another Model as follows

class Article
  belongs_to :author, :class_name => "User"
end

If I wanted to find all articles for a particular genre ordered by author I would do something like the following

articles = Article.all(:includes => [:author], :order => "users.name")

However if Article happens to have two references to User how can I sort on :author?

class Article
  belongs_to :editor, :class_name => "User"
  belongs_to :author, :class_name => "User"
end

I have tried

articles = Article.all(:includes => [:author], :order => "users.name") 
#=> incorrect results
articles = Article.all(:includes => [:author], :order => "authors.name") 
#=> Exception Thrown

My first attempted solution

A half solution is as follows. It was not totally obvious but looking at my logs I figured it out.

class Article
  belongs_to :editor, :class_name => "User"
  belongs_to :author, :class_name => "User"
end

Basically you need to do the following

articles = Article.all(:include => [:editor,:author], :order => 'articles_authors.name')

articles = Article.all(:include => [:editor,:author], :order => 'authors_articles.name') 

It is the naming of the alias that I missed (articles_authors)

The issue with this is that the following does not work although it seems like it should.

articles = Article.all(:include => [:editor,:author], :order => 'authors_articles.name')

articles = Article.all(:include => [:editor,:author], :order => 'editors_articles.name')

This may be an issue if you have a UI table and want to send the order field to the controller. So you may want to first order on author then editor. But it would fail for for one of the queries (unless you dynamically change the include too)

+1  A: 

Update - Added this to the original Question.

So I think I have nailed it. It was not totally obvious but looking at my logs I figured it out.

class Article
  belongs_to :editor, :class_name => "User"
  belongs_to :author, :class_name => "User"
end

Basically you need to do the following

articles = Article.all(:include => [:editor,:author], :order => 'articles_authors.name')

articles = Article.all(:include => [:editor,:author], :order => 'authors_articles.name') 

It is the naming of the alias that I missed (articles_authors)

Will
Also this only seems to work when sorting by authors to sort by editor the include array needs to be reversed also. That is just weird!
Will
I added this to the main question so that if anyone stumbles in here they will see that there are issues with this approach
Will
+1  A: 

This is called Table Aliasing in ActiveRecord. When the find method joins the same table more than once the alias names for the table is determined as follows:

Active Record uses table aliasing in the case that a table is referenced 
multiple times in a join. If a table is referenced only once, the standard table 
name is used. The second time, the table is aliased as 
#{reflection_name}_#{parent_table_name}. Indexes are appended for any more 
successive uses of the table name. 

Refer to the ActiveRecord documentation for more details. Search for Table Aliasing to navigate to the specific section.

KandadaBoggu
Thanks again KB! So it makes sense. I now set my table to be sorted by user if editor is selected and by author_articles if authors is selected (assuming an includes of [:editor, :author]). Works a treat.
Will