如何将枚举以字符串形式存储到Rails中的数据库

oxf4rvwz  于 2022-09-21  发布在  Ruby
关注(0)|答案(6)|浏览(135)

如何在Ruby中创建迁移,在Ruby中默认为字符串而不是Integer,我想将枚举存储到数据库中,但不想将其存储为Integer,因为这样对于想要使用相同表的另一个应用程序就没有意义了。如何用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

vs91vp4v

vs91vp4v1#

阅读enum文档,您可以看到rails使用Array的值索引,说明如下:
请注意,当使用数组时,从值到数据库整数的隐式Map是根据值在数组中出现的顺序派生的。

但也声明您可以使用Hash

还可以使用Hash显式Map属性和数据库整数之间的关系。

下面是这个例子:

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

因此,我使用rails 4.2.4sqlite3进行了测试,并创建了一个User类,其中string类型对应于sex类型,enum中的Hash类型对应于string值(我使用femmal值来区别于女性男性):

迁移:

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"
2g32fytz

2g32fytz2#

我通常会做以下事情:


# 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(see docs)的参数,可以将字符串存储在数据库中。同时,这仍然允许您使用所有很酷的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)
c7rzv4ha

c7rzv4ha3#

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

1.Rails中的enum只是integer列的 Package 器,因此在查询中使用字符串比使用整数更容易。但在数据库级别上,它都被转换为整数(由Rails自动转换),因为这是列的类型。
1.MySQL中的ENUM类型是厂商特定的列类型(例如,SQLite doesn't support it,但PostgreSQL does)。在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
fjaof16o

fjaof16o4#

请看一下这一要点,Rails不提供开箱即用的功能,因此您必须使用一个关注点:

https://gist.github.com/mani47/86096220ccd06fe46f0c09306e9d382d

6fe3ivhb

6fe3ivhb5#

以下是将枚举作为字符串添加到模型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
ar7v8xwq

ar7v8xwq6#

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

相关问题