In my Rails 7 app using Postgres, I have defined a status enum for the User model:
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_enum :status, ["pending", "active", "archived"]
create_table :users, force: true do |t|
t.enum :status, enum_type: "status", default: "pending", null: false
t.timestamps
end
end
end
app/models/user.rb
class User < ApplicationRecord
enum status: {
pending: 'Is Pending',
active: 'Is active',
archived: 'Is Archived',
disabled: 'is Disabled',
waiting: 'waiting'
}
end
Notice that unlike most of the examples on the internet, my status enum values are distinct from the keys ('pending' maps to 'Is Pending', etc)
My view code looks like this:
<%= f.collection_select(:status, enum_to_collection_select( User.defined_enums['status']), :key, :value, {selected: @user.status }, class: 'form-control') %>
The view displays correctly and submits the key back to the controller:
10:00:02 web.1 | Started POST "/users" for 127.0.0.1 at 2023-02-07 10:00:02 -0500
10:00:02 web.1 | Processing by UsersController#create as TURBO_STREAM
10:00:02 web.1 | Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"status"=>"active"}, "commit"=>"Save"}
10:00:02 web.1 | TRANSACTION (0.1ms) BEGIN
10:00:02 web.1 | ↳ app/controllers/users_controller.rb:34:in `create'
But then when the controller processes it, it attempts to save using the value. This fails because I defined my Enums in postgres to be the keys not the values:
10:00:02 web.1 | User Create (0.8ms) INSERT INTO "users" ("status", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["status", "Is active"], ["created_at", "2023-02-07 15:00:02.951440"], ["updated_at", "2023-02-07 15:00:02.951440"]]
10:00:02 web.1 | ↳ app/controllers/users_controller.rb:34:in `create'
10:00:02 web.1 | TRANSACTION (0.1ms) ROLLBACK
10:00:02 web.1 | ↳ app/controllers/users_controller.rb:34:in `create'
10:00:02 web.1 | Completed 500 Internal Server Error in 5ms (ActiveRecord: 1.0ms | Allocations: 4529)
10:00:02 web.1 |
10:00:02 web.1 |
10:00:02 web.1 |
10:00:02 web.1 | ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR: invalid input value for enum status: "Is active"
10:00:02 web.1 | CONTEXT: unnamed portal parameter $1 = '...'
10:00:02 web.1 | ):
Why is this? Shouldn't Postgres be using the keys for storage and not the values?
Isn't the point of the enum so that I can change the value displays on the frontend without changing the labels (the values) without having to modify the database?
Why does Rails translate the keys into values when saving the record?
example app here: