Skip to content

Add attribute_for_database attribute method#40456

Merged
kamipo merged 1 commit intorails:masterfrom
kamipo:attribute_for_database
Oct 30, 2020
Merged

Add attribute_for_database attribute method#40456
kamipo merged 1 commit intorails:masterfrom
kamipo:attribute_for_database

Conversation

@kamipo
Copy link
Member

@kamipo kamipo commented Oct 26, 2020

I've been reported an issue on enum from friends, they want a way to get
mapped value, but currently there is no reliable way to get that value.

If a record is loaded from database, attribute_before_type_cast works
for that. but the attribute is changed by user, the attribute method
won't work for that.

book = Book.new(status: "published")

# returns "published", but what we really want is 2.
book.status_before_type_cast

So I propose to add attribute_for_database attribute method, it
consistently returns mapped value for enum.

Originally attribute_before_type_cast on enum returned mapped value,
but it was changed in Rails 5.0 (c51f9b6) to return user supplied raw
value.

I've been reported this issue from friends, they want a way to get
mapped value, but currently that way remains lost.

So I propose to add attribute_for_database attribute method, it
behaves the same way as the previous attribute_before_type_cast for
enum.

I've been reported an issue on enum from friends, they want a way to get
mapped value, but currently there is no reliable way to get that value.

If a record is loaded from database, `attribute_before_type_cast` works
for that. but the attribute is changed by user, the attribute method
won't work for that.

```ruby
book = Book.new(status: "published")

# returns "published", but what we really want is 2.
book.status_before_type_cast
```

So I propose to add `attribute_for_database` attribute method, it
consistently returns mapped value for enum.
@kamipo kamipo force-pushed the attribute_for_database branch from 2e1a189 to 1429893 Compare October 26, 2020 10:08
@kamipo kamipo merged commit 2a0d495 into rails:master Oct 30, 2020
@kamipo kamipo deleted the attribute_for_database branch October 30, 2020 00:53
@yoelblum
Copy link

@kamipo Just wondering : why didn't we try to fix type_cast_before_attribute to work with enum and instead created this new method?

@kamipo
Copy link
Member Author

kamipo commented Nov 5, 2020

It is because returning "published" as a raw value is the expected behavior for the attribute_before_type_cast.

kamipo added a commit to kamipo/rails that referenced this pull request Mar 22, 2021
Last year, I heard about the inconveniences of ActiveRecord Enum and got
some feedback (one of those is rails#40456).

Some people have reported that in practice they are using enums for user
input and it is inconvenient to not be able to handle invalid input with
validation like other attributes.

Actually, a former colleague was overriding the attribute writer for
validation, and they had wished this inconvenience to be resolved in the
Rails.

So I propose a way to add validation on the enum attribute. This allows
people to no longer need to override the attribute writer.

Before:

```ruby
class Book < ActiveRecord::Base
  enum :status, [:proposed, :written]

  validates_inclusion_of :status, in: statuses.keys

  def status=(value)
    super
  rescue ArgumentError
    @attributes.write_cast_value("status", value)
  end
end
```

After:

```ruby
class Book < ActiveRecord::Base
  enum :status, [:proposed, :written], validate: true
end
```

Resolves rails#13971.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants