32

对于 Rails 3.0 Todo 应用程序,我有一个带有Status字段的 Tasks 模型。存储状态字段数据(字段类型)并仍然在视图(HTML 表)中显示人类可读版本的最佳方式是什么?状态可以是:

0 = 正常
1 = 活动
2 = 完成

现在我有这个:

Rails 架构在这里:

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

Rails 模型在这里:

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. 我应该将该字段存储为整数(见上文)吗?如果是这样,我如何在我的 Rails 视图中的 HTML 表格中显示正确的人类可读状态,例如在 HTML 表格中显示“活动”而不是“1”。

  2. 我应该使用枚举吗?如果是这样,这以后容易本地化吗?

  3. 我应该使用直字符串,例如“Normal”、“Active”、“Completed”

  4. 你能提供一个视图助手、控制器或视图代码的快速代码示例来完成这项工作吗?

4

6 回答 6

43

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 ','}"
于 2010-04-16T07:17:46.757 回答
6

最简单的做法是将实际字符串存储在字段中,而不是添加另一个表。根据您的观点,这要么是一个坏主意,因为您的数据库将无法充分规范化,要么是一个好主意,因为您的应用程序现在可以更有效地进行规范化。

如果您选择不这样做并将值保存在单独的表中;您需要在模型中设置关系。

class Task < ActiveRecord::Base
    has_one :status
end

class Status < ActiveRecord::Base
    belongs_to :tasks
end 

然后在您看来,您可以通过以下方式引用该值:

<%= task.status %>
于 2010-04-16T07:21:06.210 回答
3

我已将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

另一个不错的方面是,当使用常规 DB 客户端(例如:mysql 命令控制台或 phpMyAdmin)查看时,状态值显示为字符串

该插件为枚举类型提供了最佳存储和用户友好的访问。

警告:

该插件很旧并且没有维护。我在 MySQL DB 中广泛使用它。我必须修补代码才能让它在 PostgreSQL 上运行。如果你使用 MySQL,这个插件是一个不错的选择。

于 2010-04-16T07:36:39.423 回答
2

我更喜欢将“正常”、“活动”、..“完成”作为字符串存储在表中,因为:

  • 它是自文档(例如,有人可能会查看数据但从未阅读过 Rails 源代码)
  • 几乎没有(如果不是的话)性能损失
  • (仍然)很容易通过模型中的 Rails 虚拟属性或其他语言中的任何层来完成 i18n

这些天来,我倾向于尽可能多地将 Rails 常量与数据库分离。我们周围总是有一些 PHP/MSSQL/??DBA 人(他们可能不像我们那样喜欢 Rails ;-)

所以,答案不是整数也不是枚举(而是一个 varchar ;-)

于 2010-04-16T07:37:34.363 回答
1

我知道这是一个老问题,但我想提两点来自经验,特别是如果有人现在正在寻找这个(2014 - OQ 在 2010 年):

  1. 如果您正在开始一个新项目 > Rails 4(技术上是 ActiveRecord 4) - 使用 Enums - 最有效的路线。特别是如果您以后需要创建任何类型的复杂 SQL 查询。
  2. 还有更多选择 - 创建一个复合状态模型,它将保存所有其他模型的状态。使其成为 STI 模型(添加类型列) - 然后您可以创建诸如 OrderStatus < Status 或 CustomerStatus < Status 之类的东西,并且您的 Order 和 Customer 将具有 status_id 属性。这会导致更慢(!)和更繁琐(!)的查询,但是如果您正在创建一个应用程序,该应用程序将被运送给没有技术专长的客户并且他们需要某种能力通过 ActiveAdmin 之类的方式自行添加/删除状态,而不是修改您的代码库。如果您的数据层无法处理枚举,这也是一个选项。
于 2014-10-03T20:38:19.007 回答
0

使用整数来存储状态是个好主意。尽管如此,我认为接受的答案提供的代码并不优雅,因为它仅仅因为一个属性而污染了整个模型类。

我的建议是覆盖属性 getter:

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

将整数转换为字符串的逻辑只会在这个 getter 方法中,因此您不需要使类变脏。

于 2014-11-26T07:50:35.243 回答