Rails 5 更新枚举未更新

Mic*_*ans 2 ruby activerecord ruby-on-rails

enum在 Rails 和 ActiveRecord 中,我正在努力解决模型中的行为。首先,default当我运行测试时,我在 AR 迁移中在数据库级别设置的 没有生效,其次,我根本无法更新它。这是一些代码,为了简洁起见,进行了简化。

在我的模型中,枚举声明如下:

class MyModel < ApplicationRecord
  # as you can see this is a join table for different_model and another_model
  belongs_to :different_model
  belongs_to :another_model

  enum blocked: %w[no yes] # also tried with symbols, like: %i[no yes]
end
Run Code Online (Sandbox Code Playgroud)

迁移如下:

class AddBlockedToMyModel < ActiveRecord::Migration[5.2]
  def change
    add_column :my_models, :blocked, :integer, default: 0
  end
end
Run Code Online (Sandbox Code Playgroud)

我使用以下方法创建对象:

my_model = MyModel.where(different_model: @different_model, another_model: @another_model).first_or_create
Run Code Online (Sandbox Code Playgroud)

这有效,我曾经byebug检查过该记录是否持久存在(因此也有效)

然后尝试更新blocked它的枚举:

my_model.update(blocked: 'yes')
Run Code Online (Sandbox Code Playgroud)

blocked属性仍保持为nil.

我重构,尝试使用:

my_model.blocked = 'yes'
my_model.save
Run Code Online (Sandbox Code Playgroud)

并卡byebug在中间看看它是否无效,但事实并非如此。改为后.valid?返回,所以我也尝试将其改为整数,保存后仍然返回为。trueblocked'yes'1nil

仅在运行测试时才会出现此问题。当rails console一切都按照我的预期运行时——default数据库级别接管并实例化模型,并且它也可以以任何常见的blocked: 'no'AR 方式进行更新,只是不在测试中。我在这里错过了一些非常明显的东西,还是我没有得到一些奇怪的副作用?enum

DB 是 Postgres,以防有所不同。

Vla*_*gai 6

1)尽量避免使用yesandno作为枚举值。Rails 将为每个值创建方法,例如#yes?、 、#no!,并且如果您需要为不同的字段添加另一个是/否枚举,它可能无法按您的预期工作。

更好地定义它就像

enum status: [:released, :blocked]
Run Code Online (Sandbox Code Playgroud)

或者我实际上更喜欢哈希表示来明确存储哪些数据库值:

enum status: {
  released: 0,
  blocked: 1
}
Run Code Online (Sandbox Code Playgroud)

然后,不用调用update!,只需调用

your_instance.blocked!
Run Code Online (Sandbox Code Playgroud)

它会做到这一点。

2)作为一般建议,在数据库中将此字段设置为不可为空(因为我假设您不希望此字段此时具有三种状态):

change_column_null :table_name, :column_name, true
Run Code Online (Sandbox Code Playgroud)

  • 使用哈希并显式声明枚举是一个好主意,因为如果映射是隐式的,则仅对数组重新排序就会严重破坏事情。 (2认同)