简体   繁体   中英

validates_presence_of fails with enum

Using Rails 4.2.1. I have a model with a field that is an enum:

class MyModel < ActiveRecord::Base
  enum my_enum: { first_value: 0, second_value: 1 }
  validates_presence_of :my_id, :username, :my_enum
end

In the controller, I am attempting to save the model:

my_model = MyModel.find_or_initialize_by(my_id: my_id)
my_model.update(username: username, my_enum: :first_value)

Which gives me Validation failed: My enum can't be blank .

Assigning the required properties to object before saving, like this:

my_model.username = username
my_model.first_value!

or even

my_model.username = username
my_model.my_enum = 0
my_model.save!

produces the same result.

Does this mean validates_presence_of cannot be used with an enum? What is the underlying cause, if that is indeed the case?

This is not a bug. The problem was that the my_enum column was of type string , and I was trying to save an integer. Replacing

enum my_enum: { first_value: 0, second_value: 1 }

with

enum my_enum: { first_value: '0', second_value: '1' }

fixed the issue, and changing the column fixes it too.

Apparently, using strings as enums is/was an "secret undocumented feature". Please refer to this pull request (still open at the time of writing) for additional details.

I see the validates_presence_of still works with an enum. Here is my model

# production.rb
class Production < ActiveRecord::Base
  enum status: {active: 1, deactive: 0}
  validates_presence_of :status
end

And I tested your cases on rails console

Case 1:

2.2.0 :001 > Production.create!
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Status can't be blank

Case 2:

2.2.0 :001 > prod = Production.find_or_initialize_by(title: "abc")
  Production Load (0.8ms)  SELECT  "productions".* FROM "productions" WHERE "productions"."title" = ? LIMIT 1  [["title", "abc"]]
 => #<Production id: nil, title: "abc", price: nil, description: nil, status: nil, created_at: nil, updated_at: nil>
2.2.0 :002 > prod.update(price: 23, status: :active)
   (0.3ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "productions" ("title", "price", "status", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["title", "abc"], ["price", 23], ["status", 1], ["created_at", "2015-11-04 05:58:43.851364"], ["updated_at", "2015-11-04 05:58:43.851364"]]
   (0.7ms)  commit transaction
 => true

Case 3:

2.2.0 :001 > prod = Production.find_or_initialize_by(title: "def")
  Production Load (0.6ms)  SELECT  "productions".* FROM "productions" WHERE "productions"."title" = ? LIMIT 1  [["title", "def"]]
 => #<Production id: nil, title: "def", price: nil, description: nil, status: nil, created_at: nil, updated_at: nil>
2.2.0 :002 > prod.description = "bla"
 => "bla"
2.2.0 :003 > prod.save!
   (0.2ms)  begin transaction
   (0.1ms)  rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Status can't be blank

Case 4:

2.2.0 :001 > prod = Production.find_or_initialize_by(title: "def")
  Production Load (0.6ms)  SELECT  "productions".* FROM "productions" WHERE "productions"."title" = ? LIMIT 1  [["title", "def"]]
 => #<Production id: nil, title: "def", price: nil, description: nil, status: nil, created_at: nil, updated_at: nil>
2.2.0 :002 > prod.status = 0
 => 0
2.2.0 :003 > prod.save!
   (0.2ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "productions" ("title", "status", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "def"], ["status", 0], ["created_at", "2015-11-04 06:01:16.391026"], ["updated_at", "2015-11-04 06:01:16.391026"]]
   (0.7ms)  commit transaction
 => true

I'm using Rails 4.2.4.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM