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

В Rails, как я должен реализовать поле "Статус" для приложения "Задачи" - целое или перечисление?

Для приложения Rails 3.0 Todo у меня есть модель задач с полем Статус. Какой лучший способ сохранить данные поля состояния (тип поля) и по-прежнему отображать читаемую человеком версию (таблицу HTML)? Статус может быть:

0 = Нормальный 1 = Активный
2 = Завершено

Сейчас у меня есть это:

Схема рельсов Здесь:

create_table "tasks",: force = > true do | t |
    t.integer "status",: limit = > 1,: default = > 0,: null = > false

Rails Model здесь:

class Task < ActiveRecord::Base
  validates_inclusion_of :status, :in => 0..2,
    :message => "{{value}} must be 0, 1, or 2"

Rails View Here:

<h1>Listing tasks</h1>

<table>
  <tr>
    <th>Status</th>
    <th>Name</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @tasks.each do |task| %>
  <tr>
    <td><%= task.status %></td>
    <td><%= task.name %></td>
    <td><%= link_to 'Show', task %></td>
    <td><%= link_to 'Edit', edit_task_path(task) %></td>
    <td><%= link_to 'Delete', task, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

Требования

  • Сохраните состояние задачи в db, чтобы значения были легко локализованы, то есть я не уверен, что хочу сохранить "нормальный", "активный", "завершенный" как поле строки.

  • Решение должно работать с Rails 3.0.

Вопросы:

  • Должен ли я хранить это поле как целое число (см. выше)? Если да, то каким образом я могу отобразить правильный читаемый пользователем статус в таблице HTML в моем представлении Rails, например. в таблице HTML отобразите "Актив" вместо "1".

  • Должен ли я использовать перечисление? Если да, то легко ли локализовать позже?

  • Следует использовать прямые строки, например. "Нормальный", "Активный", "Завершено"

  • Можете ли вы предоставить быстрый пример кода для помощника, контроллера или кода просмотра, чтобы сделать это?

4b9b3361

Ответ 1

1.It зависит от того, сколько вы хотите оптимизировать запросы в БД.

2.Не действительно, он не поддерживается "из коробки" AR. # По Rails 4 перечисления поддерживаются из коробки.

3.IMHO вы можете использовать строки без большого штрафа за производительность (просто не забудьте добавить поле в индекс). Я бы сделал это, потому что было проще интернационализировать и поддерживать. Однако вы можете использовать целые числа, если вам нужна дополнительная производительность.

Вы можете взглянуть на 2 SO-потоки здесь и здесь, где это обсуждается.

4.Если вы хотите сохранить их как целые, вот как вы можете это сделать:

class Task << AR::Base
  NORMAL    = 1
  ACTIVE    = 2
  COMPLETED = 3


  STATUSES = {
    NORMAL    => 'normal',
    ACTIVE    => 'active',
    COMPLETED => 'completed'
  }

  validates_inclusion_of :status, :in => STATUSES.keys,
      :message => "{{value}} must be in #{STATUSES.values.join ','}"

  # just a helper method for the view
  def status_name
    STATUSES[status]
  end
end

и в поле зрения:

<td><%= task.status_name %></td>

Если вы хотите использовать строки, это упрощается:

STATUSES = ['normal', 'active', 'completed']
validates_inclusion_of :status, :in => STATUSES,
          :message => "{{value}} must be in #{STATUSES.join ','}"

Ответ 2

Самый простой способ - просто сохранить фактические строки в поле вместо добавления другой таблицы. В зависимости от вашей точки зрения это либо плохая идея, так как ваша база данных не будет достаточно нормализована или отличная идея, так как ваше приложение теперь более эффективно для нормализации.

Если вы решите не делать этого и сохранить значения в отдельной таблице; вам нужно настроить отношения в модели.

class Task < ActiveRecord::Base
    has_one :status
end

class Status < ActiveRecord::Base
    belongs_to :tasks
end 

Затем в вашем представлении вы можете ссылаться на значение на:

<%= task.status %>

Ответ 3

Я использовал Enum-Column для таких случаев использования. Плагин позволяет определить тип столбца перечисления в вашей миграции script и создает для столбца тип столбца перечисления MYSQL.

create_table :tasks do |t|
  ...
  t.enum :status, :limit => [:normal, :active, :completed], :default => :normal
  ...
end

Теперь в вашем коде вы можете сделать следующее:

task.status = "active"
task.status = :completed
p "Task status: #{task.status}" # prints Task status: completed


Task.find_by_status(:active)
Task.find_by_status("active")
Task.find_by_status(2)

Хорошо работает и с сериализацией:

task.to_xml # will result in status= active instead of status-2

Другим приятным аспектом является то, что значения статуса отображаются в виде строк при просмотре с использованием обычного клиента БД (например: консоль команд mysql или phpMyAdmin)

Плагин обеспечивает оптимальное хранение и удобный доступ для типов перечисления.

Протест:

Плагин довольно старый и не поддерживается. Я использую его широко с MySQL DB. Мне пришлось исправить код, чтобы он работал на PostgreSQL. Если вы используете MySQL, этот плагин является хорошим выбором.

Ответ 4

Я предпочитаю хранить "нормальные", "активные", "завершенные" как строку в таблице, потому что:

  • он сам документирует (например, кто-то может посмотреть на данные, но никогда не читать исходный код Rails)
  • есть небольшое (если не отрицательное) снижение производительности
  • (все же) легко сделать i18n с помощью виртуального атрибута Rails в модели или любого другого уровня на других языках.

В наши дни я стараюсь как можно больше разделить константы Rails из базы данных. Вокруг нас всегда есть люди из PHP/MSSQL/DBA (кто может не любить Rails столько, сколько мы делаем;)

Таким образом, ответ не является целым числом или перечислением (но varchar; -)

Ответ 5

Я знаю, что это старый вопрос, но я хотел упомянуть 2 очка, которые исходят из опыта, особенно если кто-то ищет это сейчас (2014 год - OQ был в 2010 году):

  • Если вы начинаете новый проект > Rails 4 (технически ActiveRecord 4) - используйте Enums - самый эффективный маршрут. Особенно, если вам нужно будет создавать любые сложные SQL-запросы позже.
  • Существует больше альтернативы - создайте составную модель состояния, которая будет содержать статусы для всех ваших других моделей. Сделайте его моделью STI (добавьте столбец типа) - тогда вы можете создавать такие вещи, как OrderStatus < Статус или CustomerStatus < Статус и ваш заказ и клиент будут иметь атрибуты status_id. Это приводит к более медленным (!) И более громоздким (!) Запросам, однако вы можете пойти по этому маршруту, если вы создаете приложение, которое будет отправлено клиенту, у которого нет технических знаний, и им потребуется какая-то способность добавлять/удалять статусы через нечто вроде ActiveAdmin самостоятельно, а не изменять свою базу кода. Это также вариант, если ваш уровень данных не может обрабатывать перечисления.

Ответ 6

Использование целого числа для хранения статуса - хорошая идея. Тем не менее, я думаю, что код, предоставленный принятым ответом, не изящен, поскольку он загрязняет весь модельный класс только из-за атрибута.

Мое предложение переопределяет атрибут getter:

def status
  {
    0 => "active",
    1 => "inactive"
  }[read_attribute(:status)] # use the read_attribute method to prevent infinite loop.
end

Логика преобразования целого в строку будет только в этом методе getter, поэтому вам не нужно делать класс грязным.