How to sort objects in a many-to-many relationship in ruby on rails?
I've been trying to deal with this problem for a couple of hours now and haven't been able to come up with a clean solution. It seems I'm not too good with rails...
Anyway, I have the following:
In code:
class Article < ActiveRecord::Base
has_many :line_aspects
has_many :aspects, :through => :line_aspects
#plus a 'name' field
end
class LineAspect < ActiveRecord::Base
belongs_to :article
belongs_to :aspect
#plus a 'value' field
end
class Aspect < ActiveRecord::Base
has_many :line_aspects
has_many :articles, :through => :line_aspects
#plus a 'name' field
end
Now, what I would like to do, is to sort these in two steps. First sort of Articles by their Articles.name, and then inside sort them by Aspect.name (note, not the middleman).
For instance, alphabetically (sorry if the notation is not correct):
[{
article => 'Apple',
line_aspects => [
{:value => 'red'}, #corresponding to the Attribute with :name => 'color'
{:value => 'small'} #corresponding to the Attribute with :name => 'shape'
]
},{
article => 'Watermelon',
line_aspects => [
{:value => 'green'}, #corresponding to the Attribute with :name => 'color'
{:value => 'big'} #corresponding to the Attribute with :name => 'shape'
]
}]
Again, note that these are ordered by the aspect name (color before shape) instead of the specific values of each line (red before green). My intention is to display these in a table in the view.
With this result:
This is the code I'm using:
<table>
<tr>
<th>Category</th>
<% @articles.each do |article| -%>
<th><%= link_to article.name, article -%></th>
<% end -%>
</tr>
<% @aspects.each do |aspect| -%>
<tr>
<td><%= aspect.name -%></td>
<% aspect.line_aspects.each do |line_aspect| -%>
<td><%= line_aspect.value %></td>
<% end -%>
</tr>
<% end -%>
</table>
I have not found a good way to do this in rails yet (without resorting to N queries). Can anyone开发者_开发技巧 tell me a good way to do it (even changing the view, if my approach is wrong)?
(I found a similar question in hyphen)
UPDATE: Here's how I'd do it in SQL:
SELECT line_aspects.value FROM line_aspects, aspects, articles
WHERE articles.id = line_aspects.article_id
AND aspects.id = line_aspects.aspect_id
ORDER BY aspects.name, articles.name
But I'd like to do it the rails way.
UPDATE: Added the view code. Which might expose my predicament a bit better.
After trying the other answer, I found a way to do it from the model. I'm not sure if this is the Right Way™, but it seems like a viable solution (to let the database engine sort it).
In the Aspect model I changed this line:
has_many :line_aspects
Into this:
has_many :line_aspects, :include => :article, :order => 'articles.name'
I'd still like to hear from more people if possible, though.
This is only a partial solution, since it doesn't solve your problem entirely.
You could use named_scope
to order the model by the respective field. Something along the lines of:
named_scope :ordered, :order => "name ASC"
It's a simple solution (at least syntax wise, not sure about complexity). The only issue I can forsee is that you cannot compond multiple named_scopes for sorting in a single query.
For the second sort, you can use Enumerable#sort_by
or array.sort
on the collection you obtained.
Hope this helps a bit :)
This query fetches all articles and eager loads its aspects and sorts them by article name and ascpect name:
@articles = Article.all(:include => [ :aspects ], :order => "articles.name asc, aspects.name asc")
精彩评论