brainspec / enumerize

Enumerated attributes with I18n and ActiveRecord/Mongoid support
MIT License
1.73k stars 190 forks source link

Bug: ActiveRecord attributes have DB values #404

Closed aomran closed 1 year ago

aomran commented 2 years ago

How to reproduce (there's a spec that demonstrates this)

  1. Add an enumerized field that is an integer in the DB and a string in code. e.g. the user status in tests
  2. Set the enumerized field using the string value
  3. Reload the AR object
  4. Note that the attributes hash will return the integer DB value not the string

This is a regression from enumerize version 2.2.2. To be specific, this bug was introduced with this PR https://github.com/brainspec/enumerize/pull/321, when a reload method was defined.

It seems that Rails calls Type#cast and this gem has not defined that method. Defining cast resolves the issue. Type#deserialize by default calls Type#cast so removing that definition should be ok.

aomran commented 2 years ago

Perhaps an even simpler demonstration:

Given:

enumerize :status, :in => { active: 1, blocked: 2 }, scope: true
user = User.new
user.status = 1
user.attributes["status"]
=> 1 
user.status = "blocked"
user.attributes["status"]
=> 2 

Given (the default implementation ActiveRecord::Enum or versions 2.2.2 or earlier of this gem):

enum status: { active: 1, blocked: 2 }
user = User.new
user.status = 1
user.attributes["status"]
=> "active"
user.status = "blocked"
user.attributes["status"]
=> "blocked"

Because values are type cast when they're set. The only reason this issue is related to reload is because your custom implementation uses setters to set the value and enumerize doesn't implement a cast method.

nashby commented 1 year ago

@aomran thanks! I merged it https://github.com/brainspec/enumerize/pull/424 here (so it doesn't include spec fix (I fixed it before))