Scenario
- Create a Books table with a string column for its cover type.
# db/schema.rb
ActiveRecord::Schema.define(version: 2021_08_19_014728) do
create_table "books", force: :cascade do |t|
t.string "cover", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["cover"], name: "index_books_on_cover"
end
end
- Define an enum in the model with the array syntax
# apps/models/book.rb
class Book < ApplicationRecord
enum cover: [:hard, :soft]
end
- Access Rails console and create an object
Book.create cover: "soft"
# => #<Book:0x00007fe231b30860
# id: 1,
# cover: nil,
# created_at: Thu, 19 Aug 2021 02:23:56.794160000 UTC +00:00,
# updated_at: Thu, 19 Aug 2021 02:23:56.794160000 UTC +00:00>
- Note that the
cover
column isnil
even though Rails created the object.
Expected behavior
I think it would be neat if Rails could infer the enum value from its key for string columns. It already does this for integers (inferring by the array position), so I don’t think it’s a stretch for us to add this. Here’s what I’m thinking:
class Book < ApplicationRecord
# for string columns, Rails would interpret it as
# enum cover: { hard: "hard" , soft: "soft" }
enum cover: [:hard, :soft]
end
Using the key as a value is probably the most common option for this case. I’ve seen a lot of apps using the following pattern to address this:
class Book < ApplicationRecord
COVER_OPTIONS = [:hard, :soft, :other]
enum cover: COVER_OPTIONS.map { |option| [option, option.to_s] }.to_h
end
This would help in those cases as well. I will tackle this if approved.
Actual behavior
Currently, it saves the object with the array index position as string, but it cannot load the value from the database, so the ActiveRecord object comes with the enum field as nil
.
System configuration
Rails version: Rails 6.1.4
Ruby version: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20]