如何将枚举作为字符串存储到rails中的数据库中

问题描述 投票:0回答:6

如何在 ruby 中创建迁移,其中默认值是字符串而不是整数,我想将枚举存储到数据库中,但我不想将其存储为整数,因为那样它对另一个应用程序没有意义想要使用同一张表。我该怎么做

default: "female"
而不是
default:0

class AddSexToUsers < ActiveRecord::Migration
  def change
    add_column :users, :sex, :integer, default: 0
  end
end
class User < ActiveRecord::Base
  enum sex: [:female, :male]
  has_secure_password
end

ruby-on-rails ruby enums
6个回答
79
投票

阅读

enum
文档,您可以看到Rails使用
Array
的值索引解释为:

请注意,使用数组时,从值到数据库整数的隐式映射是根据值在数组中出现的顺序得出的。

但也说明可以使用

Hash

还可以使用哈希显式映射属性和数据库整数之间的关系。

举例:

class Conversation < ActiveRecord::Base  
  enum status: { active: 0, archived: 1 }  
end

因此,我使用 Rails 4.2.4sqlite3 进行了测试,并创建了一个

User
类,其中
string
类型代表 sex 类型,并在
Hash
中创建了
enum
string
值(我我使用 femmal 值来区别于 femalemale):

迁移:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :sex, default: 'fem'
    end
  end
end  

型号:

class User < ActiveRecord::Base
  enum sex: { female: 'fem', male: 'mal' }
end

在控制台中:

u = User.new
#=>  #<User id: nil, sex: "fem">
u.male?
#=> false
u.female?
#=> true
u.sex
#=> "female"
u[:sex]
#=> "fem"
u.male!
# INSERT transaction...
u.sex
#=> "male"
u[:sex]
#=> "mal"

55
投票

我通常会做以下事情:

# in the migration in db/migrate/…
def self.up
  add_column :works, :status, :string, null: false, default: 'offering'
end

# in app/models/work.rb
class Work < ApplicationRecord
  ALL_STATES = %w[canceled offering running payment rating done].freeze

  enum status: ALL_STATES.zip(ALL_STATES).to_h
end

通过使用哈希作为

enum
的参数(参见文档),这会将字符串存储在数据库中。同时,这仍然允许您使用所有很酷的 Rails 辅助方法:

w = Work.new
#=>  #<Work id: nil, status: "offering">
w.rating?
#=> false
w.offering?
#=> true
w.status
#=> "offering"
w[:status]
#=> "offering"
w.done!
# INSERT transaction...
w.status
#=> "done"
w[:status]
#=> "done"

单行更新:

我完全忽略了自 Rails 1.2.6 以来我们已经有了

index_by
。这使得解决方案变得简单:

enum status: %w[canceled offering running payment rating done].index_by(&:to_sym)

或者,从 Rails 6.0.0 开始,我们有了

index_with

enum status: %i[canceled offering running payment rating done].index_with(&:to_s)

20
投票
Rails 中的

enum
和 MySQL 中的
ENUM
type
是两个不同的东西。

    Rails 中的
  1. enum
    只是
    integer
    列的包装器,因此您可以更轻松地在查询中使用字符串,而不是整数。但在数据库级别,它全部转换为整数(由 Rails 自动转换),因为这是列的类型。

  2. MySQL 中的
  3. ENUM
    类型是特定于供应商的列类型(例如,SQLite 不支持它,但 PostgreSQL )。在 MySQL 中:

ENUM 是一个字符串对象,其值是从允许值列表中选择的,这些值是在表创建时在列规范中显式枚举的。

CREATE TABLE shirts (
    name VARCHAR(40),
    size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
  ('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name    | size   |
+---------+--------+
| t-shirt | medium |
+---------+--------+

对于迁移,您需要执行以下操作:

class AddSexToUsers < ActiveRecord::Migration
  def change
    add_column :users, :sex, "ENUM('female', 'male') DEFAULT 'female'"
  end
end

1
投票

将枚举作为字符串添加到模型中的步骤

Company

bin/rails g migration AddStatusToCompanies status
class AddStatusToCompanies < ActiveRecord::Migration[7.0]
  def change
    add_column :companies, :status, :string, null: false, default: 'claimed'
    add_index  :companies, :status
  end
end
bin/rails db:migrate
  • 值是字符串(符号不起作用)
  • 添加默认值
  • 添加前缀
enum status: {
  claimed: 'claimed',
  unverified: 'unverified',
  verified: 'verified',
}, default: 'claimed'
  • 添加验证(否则会引发sql异常)
validates :status, inclusion: { in: statuses.keys }, allow_nil: true

0
投票

由 Once Campfire 源代码中的 DHH 提供,您可以将 .index_by(&:itself) 作为字符串 ActiveRecord 枚举最易读的选项。

class User < ActiveRecord::Base
  enum sex: %w[female male].index_by(&:itself)
end

Rails 文档 现在正确地指出您可以对字符串枚举使用哈希,但请注意查询字符串而不是整数列会更慢。如果您经常对该列进行排序或过滤,则可以向该列添加索引。


-1
投票

据我所知,标准 Rails 枚举是不可能的。看看https://github.com/lwe/simple_enum,它的功能更加丰富,并且还允许将enum值作为字符串存储到DB(列类型字符串,即DB中的varchar)。

© www.soinside.com 2019 - 2024. All rights reserved.