I want to have a default value for my enum field to prevent it from being nil. I did the following:
# db/schema.rb
create_table "templates", force: :cascade do |t|
t.integer "status"
end
# app/models/template.rb
class Template < ActiveRecord::Base
STATUSES = [:draft, :published]
enum status: STATUSES
after_initialize :init
def init
self.status ||= STATUSES.index(:draft)
end
end
I get the expected results in my local environment. But not quite in heroku. I need it to be the default value draft
after updating status to nil
, but in this context it becomes nil
and yet the published
scope still includes the updated row.
$ heroku run rails console
> Template.published.pluck :id
=> [1, 2]
> Template.find(1).update(status:nil)
Template Load (4.4ms) SELECT "templates".* FROM "templates" WHERE "templates"."id" = $1 LIMIT 1 [["id", 1]]
Template Load (4.4ms) SELECT "templates".* FROM "templates" WHERE "templates"."id" = $1 LIMIT 1 [["id", 1]]
(1.7ms) BEGIN
(1.7ms) BEGIN
(1.1ms) COMMIT
(1.1ms) COMMIT
=> true
> Template.find(1).status
=> nil
> Template.published.pluck :id
=> [1, 2]
Is this the correct use case to use an enum? Is there a peculiarity with my heroku environment that I'm missing out?
Starting from Rails 6.1, it is possible to set a default enum value right in the model. For example:
class Template < ActiveRecord::Base
enum status: [:draft, :published], _default: :draft
end
Here is a link to relative PR and a link to the docs.
Starting from Rails 7, there is no more need to use leading underscore. For example:
class Template < ActiveRecord::Base
enum :status, [:draft, :published], default: :draft
end
Here is a link to relative PR and a link to the docs.
You can set the default value from the database declaration.
create_table :templates do |t|
t.column :status, :integer, default: 0
end
And then, map the relationship as following
class Template < ActiveRecord::Base
enum status: { draft: 0, published: 1 }
end
Rails 6.1 allowed the setting of a default enum value right in the model.
Rails 7 introduced new syntax for defining an enum. E.g.
class Template < ActiveRecord::Base
enum :status, [:draft, :published], default: :draft
end
Here is a link to the relevant PR and a link to the edge docs.
Another way of doing it is:
class Template < ActiveRecord::Base
before_create :set_default_status
enum :status: { draft: 0, published: 1 }
def set_default_status
self.status ||= :draft
end
end
In this case, you can keep your migration
file simple:
...
t.integer :status
...
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