Ruby on rails Rails 5更新枚举未更新

Ruby on rails Rails 5更新枚举未更新,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,在Rails和ActiveRecord中,我正在努力解决模型中enum的行为。首先,我在AR迁移中在数据库级别设置的default在我运行测试时没有生效,其次,我根本无法更新它。下面是一些代码,为了简洁起见进行了简化 在我的模型中,枚举声明如下: class MyModel?一般不需要,但是如果你手动改变了迁移,Rails不能推断测试数据库必须重新初始化。你也可以通过:(已阻止:我的_模型。已阻止[:是]“关于布尔值在不断变化的需求中出现问题的说法是绝对正确的。您经常看到人们创建可为空的三状态布

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

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

class MyModel
迁移情况如下:

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

my\u model=MyModel.where(不同的\u model:@不同的\u model,另一个\u model:@另一个\u model)。首先\u或\u创建
这是有效的,我使用
byebug
来检查该记录是否被持久化,并且它是否有效(因此也是有效的)

然后尝试更新其上的enum
blocked

my_model.update(已阻止:“是”)
但是
blocked
属性保持为
nil

我进行了重构,尝试使用:

my_model.blocked='yes'
my_model.save

和Cux<代码> Byebug <代码>中间,看看它是否无效,它不是。code>.valid?在将

blocked
更改为
'yes'
后返回
true
,因此我也尝试将其更改为整数
1
,保存后,它仍然返回到
nil

此问题仅在运行测试时发生。在
rails控制台中运行时
一切正常-数据库级别的
默认值
接管并实例化模型,并使用
阻塞:'no'
,它也可以以任何常规AR方式更新,只是不在测试中。我是否遗漏了一些非常明显的东西,或者是我没有得到的
enum
的一些奇怪的副作用

DB是Postgres,以防产生影响。

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

最好像这样定义它

enum status: [:released, :blocked]
或者我实际上更喜欢哈希表示,以明确存储哪些DB值:

enum status: {
  released: 0,
  blocked: 1
}
然后,不要调用
update,打电话就可以了

your_instance.blocked!
它会成功的

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

change_column_null :table_name, :column_name, true
1) 尽量避免将
yes
no
作为枚举值。Rails将为每个值创建方法,例如
#yes?
#no,如果您需要为不同的字段添加另一个yes/no枚举,它可能无法正常工作

最好像这样定义它

enum status: [:released, :blocked]
或者我实际上更喜欢哈希表示,以明确存储哪些DB值:

enum status: {
  released: 0,
  blocked: 1
}
然后,不要调用
update,打电话就可以了

your_instance.blocked!
它会成功的

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

change_column_null :table_name, :column_name, true

为什么不对blocked使用布尔真/假值而不是enum?同样对于enum,在散列样式中使用它们是一个很好的实践,比如
enum blocked:{no:0,yes:1}
感谢@nuaky的评论,我最初考虑过这一点,但已经读到boolean可能会因需求的变化而出现问题。这个属性是通过第三方API获得的,我只是想在某一点上需求可能会发生变化。但是,不值得浪费太多的时间,所以我现在可以用一个布尔值来考虑,如果时间到了,就考虑重构。谢谢你关于散列的注释,注意到了!您是否运行了rake db:test:prepare
?通常不需要,但如果您手动更改迁移,rails无法推断测试数据库必须重新初始化。您还可以通过以下方式更新它:
my\u model.update(blocked:my\u model.blocked[:yes]“
关于布尔值在不断变化的需求中存在问题的说法是完全正确的。您经常看到人们创建可为空的三状态布尔值列,这是一个很大的禁忌,因为布尔逻辑发生故障或向对象添加了大量潜在冲突的开关。为什么不使用布尔值true/false来表示blocked而不是enum?同样对于枚举,在哈希样式中使用它们是一个很好的实践,比如
enum blocked:{no:0,yes:1}
感谢@nuaky的评论,我最初考虑过这一点,但我已经了解到布尔值可能会随着需求的变化而出现问题。这个属性是通过第三方API获得的,我只是认为在某个时候需求可能会发生变化。但是,这不值得浪费太多时间,所以我可能会选择布尔值现在,并考虑一个重构,如果时间到了,谢谢你的注释,注意,你运行了<代码> RAK:DB:测试:准备< /COD>?一般不需要,但是如果你手动改变了迁移,Rails不能推断测试数据库必须重新初始化。你也可以通过:(已阻止:我的_模型。已阻止[:是]“
关于布尔值在不断变化的需求中出现问题的说法是绝对正确的。您经常看到人们创建可为空的三状态布尔值列,这是一个很大的禁忌,因为布尔逻辑发生故障,或者向对象添加了大量可能冲突的开关。使用哈希并显式声明枚举是一个好主意,因为对数组进行重新排序将破坏一切