Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cop idea: Suggest using validate option for enums since Rails 7.1 #1285

Open
ybiquitous opened this issue May 27, 2024 · 1 comment
Open

Comments

@ybiquitous
Copy link
Contributor

ybiquitous commented May 27, 2024

Is your feature request related to a problem? Please describe.

Rails 7.1 has added the support Enum validation implemented by PR rails/rails#49100. For example:

class Contract < ApplicationRecord
  enum :status, [:in_progress, :completed], validate: true
end

As we can see many positive reactions in rails/rails#49100, many people seem to love the feature. So, I think it's worth adding a new cop to suggest using the validate option for enums.

Describe the solution you'd like

The new cop would suggest validate as below if enabled:

class User < ActiveRecord::Base
  # bad
  enum :status, [:enabled, :disabled]
# ^^^^ Prefer the `:validate` option over `ArgumentError`.

  # good
  enum :activity, [:active, :inactive], validate: true
end

But first, I believe this cop should be disabled by default because the code's behavior would change. We could enable the cop by default when many people are familiar with this feature (I hope this cop can help that 😁).

Describe alternatives you've considered

I have no alternatives for now.

Additional context

Here is a reproduction of this feature, although it's a bit too long: ⬇️

Reproduction code

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "rails", "~> 7.1"
  gem "sqlite3", "~> 1.7"
end

require "active_record"
require "minitest/autorun"
require "logger"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

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

class User < ActiveRecord::Base
  # bad (< Rails 7.1)
  enum :status, [:enabled, :disabled]

  # good (>= Rails 7.1)
  enum :activity, [:active, :inactive], validate: true
end

class UserTest < Minitest::Test
  def setup
    @user = User.new
  end

  def test_status
    assert_raises(ArgumentError, "'foo' is not a valid status") do
      @user.status = :foo
    end
  end

  def test_activity
    @user.activity = :foo
    refute @user.valid?
    assert_equal ["Activity is not included in the list"], @user.errors.full_messages

    @user.activity = :active
    assert @user.valid?
  end
end

If you have Docker, you can save this code to test.rb in any directory and run it easily:

docker run --rm -it -v ${PWD}:/work -w /work ruby:3.3 ruby test.rb

Thanks for reading.

@yykamei
Copy link

yykamei commented May 27, 2024

But first, I believe this cop should be disabled by default because the code's behavior would change.

I support this idea. The Cop is definitely useful, but this Cop might suggest the code below:

class Attend < ActiveRecord::Base
  enum size: [:yes, :no, :maybe]

  validates :size, inclusion: { in: sizes.keys }
end

Borrowed from https://stackoverflow.com/questions/8146965/how-do-i-specify-and-validate-an-enum-in-rails

If this Cop suggest in the code, developers might feel false-positive.

That's why it's great to make the Cop disabled by default 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants