В Rails, как мне реализовать поле Status для приложения Tasks - целочисленное или перечисление? - PullRequest
31 голосов
/ 16 апреля 2010

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

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

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

Схема Rails Здесь:

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

Модель рельсов здесь:

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

Рельсы Смотреть здесь:

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

Требования

  1. Сохранение статуса задачи в БД, так что значения легко локализуются, т. Е. Я не уверен, что хочу сохранить «обычное», «активное», «выполненное» как строковое поле.

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

Вопросы:

  1. Должен ли я хранить поле как целое число (см. Выше)? Если да, то как мне отобразить правильное удобочитаемое состояние в таблице HTML в моем представлении Rails, например, покажите «Active» вместо «1» в таблице HTML.

  2. Должен ли я использовать enum? Если так, это легко локализовать позже?

  3. Должен ли я использовать прямые строки, например, «Обычный», «Активный», «Завершено»

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

Ответы [ 6 ]

42 голосов
/ 16 апреля 2010

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

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

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

Вы можете взглянуть на 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 ','}"
6 голосов
/ 16 апреля 2010

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

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

class Task < ActiveRecord::Base
    has_one :status
end

class Status < ActiveRecord::Base
    belongs_to :tasks
end 

Тогда, по вашему мнению, вы можете ссылаться на значение следующим образом:

<%= task.status %>
3 голосов
/ 16 апреля 2010

Я использовал Enum-Column для таких случаев использования. Плагин позволяет вам определить тип столбца перечисления в вашем скрипте миграции и создать тип столбца перечисления 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. Мне пришлось исправлять код, чтобы он работал на PostgreSQL. Если вы используете MySQL, этот плагин является хорошим выбором.

2 голосов
/ 16 апреля 2010

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

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

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

Итак, ответ не целое и не enum (а varchar; -)

1 голос
/ 04 октября 2014

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

  1. Если вы начинаете новый проект> Rails 4 (технически ActiveRecord 4) - используйте Enums - самый эффективный маршрут. Особенно, если вам нужно создать какой-либо сложный запрос SQL позже.
  2. Существует еще одна альтернатива - создайте составную модель Status, которая будет содержать статусы для всех ваших других моделей. Сделайте это моделью STI (добавьте столбец типа) - тогда вы сможете создавать такие вещи, как OrderStatus
0 голосов
/ 26 ноября 2014

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

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

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

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

...