Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is rails 5 adding nextval method in schema file?

After upgrading to Rails 5 my schema file keeps getting altered when running db:migrate. Rails is changing:

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

to:

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

It only occurs on this one model. Why is rails implementing nextval on this particular model? And, why is it getting the model name wrong (lessons_id_seq should be flightlessons_id_seq). Manually changing it to flightlessons_id_seq, however, results in the same no relation error.

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

To proceed, I simply alter the schema.rb file back to what that line 'should' be. Then, I can migrate or test:prepare or whatever until the next time rails alters it back to using the nextval method.

Thank you for any insight into this.

like image 557
hellion Avatar asked Jul 29 '16 19:07

hellion


1 Answers

This is a bit long of an answer, so I've broken it into sections. Buckle up!

My theory

My guess is that your development database does contain the lessons_id_seq sequence, and that its definition of flightlessons.id is set to depend on it (i.e., exactly what Rails is putting into your schema file).

How and why? You likely renamed the lessons table to flightlessons at some point in the past, but that rename didn't change the sequence that the table depended on -- and since schema.rb does not record sequences, the lessons_id_seq sequence does not get copied to your test database, and thus you get this error.

To verify my theory, run rails db and try the following commands:

\d lessons_id_seq

This should return the definition of that sequence. Then, try:

\d flightlessons

And look at the definition of the id column. I expect it to include DEFAULT nextval('lessons_id_seq').

Fixes

The easiest way to fix this is to switch to using structure.sql instead of schema.rb (see the docs). This will carry over the exact state of your database and avoid any interference or interpretation by Rails, which is what's causing your current issue. I always recommend structure.sql for production systems.

However, you can also go into your development database and change the sequence name:

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

This would be a terrible idea on a production system, but if your issue is just local, it should rectify your current database state with your schema.rb and thus address your current problem. You may wish to encode that into a migration, if you want rails db:drop db:create db:migrate to work on a fresh app.

Why now?

The behavior where Rails is dumping out the default value for your table's primary key may very well be new in Rails 5. Previously, Rails may have just trusted that your ID column had a sane default, and ignored whatever value it actually saw. But I haven't done the research to see if that's true or not.

like image 153
Robert Nubel Avatar answered Sep 16 '22 13:09

Robert Nubel