I am running the given below migation to add an extra value to my blood
enum.
class AddTypesToBlood < ActiveRecord::Migration[5.2]
def up
execute <<-SQL
ALTER TYPE blood ADD ATTRIBUTE 'NA';
SQL
end
def down
execute <<-SQL
ALTER TYPE blood DROP ATTRIBUTE 'NA';
SQL
end
end
But the above migration is throwing error. Pease have look to terminal screen shot for error.
1 Create type – This is defined as create enum data type using create type in PostgreSQL. 2 Name of enum type – This is define as create enum type and use this in table at the time of table creation. ... 3 Name of table – This is defined as name of table on which column we have defining enum data type. More items...
ALTER TYPE ... ADD VALUE (the form that adds a new value to an enum type) cannot be executed inside a transaction block. Comparisons involving an added enum value will sometimes be slower than comparisons involving only original members of the enum type.
Alter type – We can alter enum type after creation, we can modify the enum type by using the alter type command. We can add a new value into the enum data set to use the same into the table. Add value – This is defined as add a new value to the enum type by using the alter type command.
The slowdown is usually insignificant; but if it matters, optimal performance can be regained by dropping and recreating the enum type, or by dumping and reloading the database. To add a new value to an enum type in a particular sort position:
Since you're going the route of adding a new enum value through SQL, I'm going to guess that you defined the column to be an enum also through SQL. So using Postgres's Documentation:
ALTER TYPE name ADD VALUE new_enum_value [ { BEFORE | AFTER } existing_enum_value ]
Give this a shot:
def up
execute <<-SQL
ALTER TYPE blood ADD VALUE 'NA';
SQL
end
def down
execute <<-SQL
ALTER TYPE blood DROP VALUE 'NA';
SQL
end
Another way of going about enums in Rails is by having the enum defined in the model. So what you can do is have your model have an attribute (called blood
) be of type integer
. Then in the model you can do:
class Model < ApplicationRecord
enum blood: [
:A,
:B,
:AB,
:O,
:NA
]
end
This way when you want to modify the values of the enum, you don't have to create another migration. Another benefit to doing it this way is you get to use strings (or symbols) as the value for the enum. I.e.:
# Both work
model.update_attributes(blood: 'O')
model.update_attributes(blood: :O)
And when you access the blood
attribute, you still get a string back:
puts model.blood # => "O"
If you take a look at the documentation, you'll see that the syntax is
ALTER TYPE blood ADD VALUE 'NA';
There is no way to drop a value from an enum type in PostgreSQL, so you won't be able to undo that change.
If an attribute has a value range that changes, don't use enum types for it.
The accepted answer cannot work since there's no such thing as DROP VALUE
(and there wasn't in previous Postgres versions)
The steps are basically:
Here's an example of the fundamental steps:
https://www.munderwood.ca/index.php/2015/05/28/altering-postgresql-columns-from-one-enum-to-another/
Based on Rich Steinmetz's answer, here is what my reversible migration for something like this looks like.
This assumes you have a Human
model with a blood_type
column which uses the blood
type with four possible values (A
, B
, AB
and O
) and a default value of O
, and you are trying to add NA
as a value.
class AddTypeToBlood < ActiveRecord::Migration[6.1]
def up
execute <<-DDL
ALTER TYPE blood ADD VALUE 'NA';
DDL
end
def down
execute <<-DDL
CREATE TYPE old_blood AS ENUM (
'A', 'B', 'AB', 'O'
);
DDL
add_column :humans, :old_blood_type, :old_blood, null: false, default: "O"
Human.where(blood_type: "NA").update_all(blood_type: "O")
Human.all.each { |human| human.update(old_blood_type: human.blood_type) }
remove_column :humans, :blood_type
rename_column :humans, :old_blood_type, :blood_type
execute <<-DDL
DROP TYPE blood;
ALTER TYPE old_blood RENAME TO blood;
DDL
end
end
NB: If you want to change the default value for the blood_type
column to NA
, you must do so in a separate migration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With