Как отсортировать объекты в отношениях многие ко многим в ruby ​​на рельсах? - PullRequest
2 голосов
/ 14 мая 2010

Я уже пару часов пытаюсь решить эту проблему и не смог найти чистого решения. Кажется, я не очень хорош с рельсами ...

В любом случае, у меня есть следующее:

Diagram

В коде:

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

Теперь, что я хотел бы сделать, это отсортировать их в два этапа. Сначала сортируйте Статьи по их названию Articles.name, а затем внутри сортируйте их по Aspect.name (обратите внимание, а не посредник).

Например, в алфавитном порядке (извините, если запись не верна):

[{
   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'
   ]
}]

Опять же, обратите внимание, что они упорядочены по имени аспекта (цвет перед формой) вместо конкретных значений каждой линии (красный перед зеленым). Мое намерение состоит в том, чтобы отобразить их в виде таблицы.

С этим результатом:

Table

Это код, который я использую:

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

Я еще не нашел хорошего способа сделать это в рельсах (не прибегая к N запросам). Может кто-нибудь сказать мне хороший способ сделать это (даже изменить представление, если мой подход неверен)?

(я нашел похожий вопрос в дефисе )

ОБНОВЛЕНИЕ: Вот как я это сделаю в 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

Но я бы хотел сделать это путём рельсов.

ОБНОВЛЕНИЕ: добавлен код просмотра. Что может раскрыть мое затруднение немного лучше.

Ответы [ 3 ]

3 голосов
/ 14 мая 2010

Попробовав другой ответ, я нашел способ сделать это из модели. Я не уверен, что это правильный путь ™, но это кажется жизнеспособным решением (позволить ядру базы данных отсортировать его).

В модели Aspect я изменил эту строку:

has_many :line_aspects

В это:

has_many :line_aspects, :include => :article, :order => 'articles.name'

Я все же хотел бы услышать от большего количества людей, если это возможно.

1 голос
/ 14 мая 2010

Это только частичное решение, так как оно не решит вашу проблему полностью.

Вы можете использовать named_scope, чтобы упорядочить модель по соответствующему полю. Что-то вроде: named_scope :ordered, :order => "name ASC"

Это простое решение (по крайней мере, с точки зрения синтаксиса, не уверенное в сложности). Единственная проблема, которую я могу заметить, это то, что вы не можете объединить несколько named_scopes для сортировки в одном запросе.

Для второй сортировки вы можете использовать Enumerable#sort_by или array.sort в коллекции, которую вы получили.

Надеюсь, это поможет немного:)

0 голосов
/ 14 мая 2010

Этот запрос выбирает все статьи и активно загружает их аспекты и сортирует их по имени статьи и имени аспекта:

@articles = Article.all(:include => [ :aspects ], :order => "articles.name asc, aspects.name asc")
...