将伪枚举模型重构为枚举

Posted

技术标签:

【中文标题】将伪枚举模型重构为枚举【英文标题】:Refactoring pseudo-enum models to enums 【发布时间】:2022-01-16 15:48:32 【问题描述】:

我有一个名为article_status 的模型,它只是为文章提供状态。我想删除这个article_status 表并直接在article 模型中使用enum

所以,我创建了一个新的迁移,但我的问题是如何编写 SQL 来更新列。

class AddStatusToArticles < ActiveRecord::Migration[6.1]
  def change
    add_column :articles, :status, :integer
    add_index :articles, :status

    execute <<~SQL
      # Write SQL here
    SQL

    change_column :articles, :status, :integer, null: false
  end
end

对于 SQL 部分,我想要相当于:

Article.all.each do |article|
  article.update_columns(status: article.article_status.name.parameterize.underscore)
end

在我的article 模型中:

enum status:  draft: 0, in_review: 1, reviewed: 2, published: 3, deleted: 4 , _default: :draft

我像这样添加了enum

PS:我使用 Postgres 作为我的数据库。

【问题讨论】:

表中有多少条记录?将逻辑转换为纯 SQL 真的值得吗?旧表中是否只有五个不同的值,还是 SQL 也需要能够处理其他值? @spickermann 我有belongs_to 关联和一些我想删除的验证。如果我删除它并像上面那样编写特定于 ruby​​ 的代码,它会引发一个错误,提示未定义方法 article_status_id。它的记录很少,但由于这个错误,我选择了 SQL。它只有五个不同的值。 如果你已经删除了article_status_id,你怎么知道什么状态属于什么文章?那如何在 SQL 中解决呢? 我没有删除article_status_id 列,也没有删除article_status 表。我刚刚删除了特定于 Rails 的代码。 belongs_to :article_status。通过这样做并编写 Rails 逻辑而不是 SQL,我得到了第一条评论中提到的错误。 【参考方案1】:

我会这样做:

statuses = ArticleStatus
  .pluck(:id, :name)
  .map  |(id, name)| [id, name..parameterize.underscore] 
  .to_h

Article.find_each do |article|
  article.update_columns(status: statuses[article. article_status_id])
end

【讨论】:

以上是关于将伪枚举模型重构为枚举的主要内容,如果未能解决你的问题,请参考以下文章

如何在Django中基于枚举为模型字段设置默认值?

如何从可枚举转换为特定模型

Python - 将枚举转换为 Django 模型。CharField 选择元组 [重复]

java枚举在android项目应用

移动到 cocoapod 时,Swift Routing 枚举崩溃

为啥使用常量而不是枚举?