为什么rails 5在模式文件中添加nextval方法?

升级到Rails 5后,我的架构文件在运行db:migrate时不断被更改。 Rails正在发生变化:

create_table "flightlessons", force: :cascade do |t| 

至:

 create_table "flightlessons", id: :integer, default: -> { "nextval('lessons_id_seq'::regclass)" }, force: :cascade do |t| 

它只发生在这一个模型上。 为什么rails在这个特定型号上实现nextval? 而且,为什么它的模型名称错误(lessons_id_seq应该是flightlessons_id_seq)。 但是,手动将其更改为flightlessons_id_seq会导致相同的无关系错误。

 PG::UndefinedTable: ERROR: relation "lessons_id_seq" does not exist 

为了继续,我只需将schema.rb文件更改回该行应该是什么。 然后,我可以迁移或测试:准备或其他什么,直到下一次rails将其改回使用nextval方法。

感谢您对此的任何见解。

这有点长的答案,所以我把它分成了几个部分。 系好安全带!

我的理论

我的猜测是你的开发数据库确实包含了lessons_id_seq序列,并且它的flightlessons.id定义被设置为依赖于它(即,确切地说Rails放入你的模式文件中)。

怎么样和为什么? 您可能在过去的某个时刻将lessons表重命名为flightlessons ,但重命名并未更改表所依赖的顺序 – 并且由于schema.rb不记录序列,所以lessons_id_seq序列不会复制到您的测试数据库,从而得到此错误。

要validation我的理论,请运行rails db并尝试以下命令:

 \d lessons_id_seq 

这应该返回该序列的定义。 然后,尝试:

 \d flightlessons 

并查看id列的定义。 我希望它包含DEFAULT nextval('lessons_id_seq')

修复

解决此问题的最简单方法是切换到使用structure.sql而不是schema.rb (请参阅文档 )。 这将inheritance数据库的确切状态,避免Rails的任何干扰或解释,这是导致您当前问题的原因。 我总是推荐用于生产系统的structure.sql

但是,您也可以进入开发数据库并更改序列名称:

 ALTER SEQUENCE lessons_id_seq RENAME TO flightlessons_id_seq; ALTER TABLE flightlessons ALTER COLUMN id SET DEFAULT nextval('flightlessons_id_seq'); 

这对于生产系统来说是一个糟糕的想法,但如果您的问题只是本地问题,它应该使用schema.rb纠正您当前的数据库状态,从而解决您当前的问题。 您可能希望将其编码为迁移,如果您需要rails db:drop db:create db:migrate以在新应用程序上运行。

为什么现在?

在Rails 5中,Rails倾销出表的主键的default值的行为可能是新的。以前,Rails可能只是相信你的ID列有一个合理的默认值,并忽略它实际看到的任何值。 但我还没有做过研究,看看这是不是真的。