#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
#41516 introduced an unexpected change in the use of
enum.Enum's
serializemethod can convert a string/symbol value to it's matching integer value as mapped in an ActiveRecord object'senumdeclaration. Before the change, if you perform awhereorfindfor a value that is not defined in the object'senum, the sql query generated will contain the string originally passed in. After the change, the query is generated withnilinstead 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
enumwould 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.