Подтвердить что ты не робот

Rails: Пользовательский порядок записей

Рубины или рельсы предоставляют метод упорядочения строк в указанном порядке? Скажем, что у меня есть следующие приоритеты: "Тяжелый, Высокий, Средний, Низкий".

Эти приоритеты не будут часто меняться (если вообще). У меня есть модель задачи с приоритетным столбцом:

tasks
  - id (integer)
  - name (string)
  - priority (string)

Я хотел бы получить массив всех заданий, упорядоченных по приоритету. Поскольку логический порядок не соответствует алфавитному порядку, его невозможно просто упорядочить по столбцу приоритета:

Task.all(:order => :priority)

То, что я сделал, это создать модель Priority и определить ассоциации: Task принадлежит_приоритету. В таблице приоритетов я затем присваивал каждому имени приоритета значение и упорядочивался по этому значению. Есть лучший способ сделать это? Я бы предпочел не иметь таблицу приоритетов вообще и объявить константу PRIORITY (как хэш) или просто указать приоритет как строку в таблице задач.

4b9b3361

Ответ 1

Переключитесь на целое число, как сказал Аарон, тогда вы, вероятно, захотите использовать default_scope.

Например:

class Task < ActiveRecord::Base
  default_scope :order => 'tasks.position' # assuming the column name is position
  ...

При использовании области по умолчанию вам не нужно указывать порядок сортировки в любом вызове метода поиска - задачи будут автоматически отсортированы.

Ответ 2

Вы можете использовать оператор case в своем предложении where. Это немного уродливо, но должно работать:

class Task
  PRIORITIES_ORDERED = ['high', 'medium', 'low']

  # Returns a case statement for ordering by a particular set of strings
  # Note that the SQL is built by hand and therefore injection is possible,
  # however since we're declaring the priorities in a constant above it's
  # safe.
  def self.order_by_case
    ret = "CASE"
    PRIORITIES_ORDERED.each_with_index do |p, i|
      ret << " WHEN priority = '#{p}' THEN #{i}"
    end
    ret << " END"
  end

  named_scope :by_priority, :order => order_by_case

end

И затем, когда вы хотите, чтобы они были упорядочены по приоритету, вы можете сделать что-то вроде этого:

Task.all.by_priority

Конечно, как говорили другие люди, очистить внешний ключ от таблицы Priority вместо столбца текстовой строки. В таблице Priorty вы можете добавить столбец позиции как целое число, которое вы можете отсортировать, и существуют плагины, чтобы сделать это проще.

Ответ 3

Здесь приведена обновленная версия, которая работает для рельсов 4.1 и немного настроена:

  PRIORITIES_ORDERED = ['Unknown', 'Critical', 'Warning', 'Ok']
  def self.order_by_case
    ret = "CASE"
    PRIORITIES_ORDERED.each_with_index do |p, i|
      ret << " WHEN status = '#{p}' THEN #{i}"
    end
    ret << " END"
  end

  scope :order_by_priority, -> { order(order_by_case) }

Ответ 4

Я бы использовал целые числа в db. Легче сортировать и индексировать, а затем переопределять атрибут getter и setter для использования символов для внешнего интерфейса.

Ответ 5

Если изменение схемы для использования целочисленного приоритета не является опцией, вы также можете определить собственный метод <= > в задаче для определения порядка сортировки.

class Task

  PRIORITIES = {
    :high => 3,
    :med  => 2,
    :low  => 1,
  }

  def <=> (other)
    PRIORITIES[self.priority] <=> PRIORITIES[other.priority]
  end

end

Недостатком этого является то, что вам нужно выполнить сортировку на стороне Ruby, а не позволить вашей базе данных сделать это для вас, что исключает использование default_scope. Поверхность заключается в том, что в любой момент, когда вы вызываете sort в Array of Tasks, порядок будет выдаваться правильно (или, если вы хотите только индивидуальный заказ в одном конкретном месте, вы можете использовать sort_by).

Ответ 6

Я бы предложил использовать act_as_list (http://github.com/rails/acts_as_list/tree/master), который добавит поле позиции к вашему объекту, но также даст вам все методы перемещения вещей вверх и вниз по списку, сохраняя порядок правильно.

Если приоритеты никогда не будут изменяться, лучше сделать приоритет поле в таблице задач. Проблема в том, что вам тогда нужно иметь возможность сортировать по приоритету. Для этого у вас есть несколько вариантов, но все, что вы выберете, должно быть сделано с помощью db.

Ответ 7

Просто чтобы решить ваш конкретный вопрос: вы можете заказать его по последней букве.

Север (e), Hig (h), Mediu (m), Lo (w)

вы можете сделать это в rails или sql:

order by RIGHT(priority, 1)

Я выбираю этот подход, потому что

  • это самый простой способ.
  • Вы упомянули, что он не изменится.

подход может быть недостаточно гибким, но тоже я, я стараюсь не обобщать проблему, если это необходимо