Skip to content

Enum serialization changes caused an undocumented MySQL behavior change #41595

@leequarella

Description

@leequarella

#41516 introduced an unexpected change in the use of enum.

Enum's serialize method can convert a string/symbol value to it's matching integer value as mapped in an ActiveRecord object's enum declaration. Before the change, if you perform a where or find for a value that is not defined in the object's enum, the sql query generated will contain the string originally passed in. After the change, the query is generated with nil instead of the string value.

This results in a behavioral change when using MySQL. When you pass a string to a MySQL int column, it is cast as a 0. This essentially means that the with the old behavior, any value requested that is not in the enum would default to the first value. With the new behavior, any value not in the enum will return nothing.

The change adds consistency to MySQL and sqlite integrations (the only two I've tested so far), so overall it feels like the right move, but since this seems to be a breaking change I don't know exactly how it should be handled (changelog? deprecation?).

Here as an example. Before the change this test passes MySQL and fails sqlite, afterwards it fails in both.

ActiveRecord::Schema.define do
  create_table :authors, force: true do |t|
    t.column :status, :integer
  end
end

class Author < ActiveRecord::Base
  enum status: { active: 0, inactive: 1 }
end

class BugTest < Minitest::Test
  def test_not_in_enum
    author = Author.create(status: :active)
    assert author.persisted?
    assert_equal Author.find_by(status: :retired), author
  end
end

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions