问题描述
我有这个(简化的)担忧:
module Nobi::Personable
extend ActiveSupport::Concern
included do
belongs_to :person,:autosave => true delegate :gender,:gender=,:gender_changed?,:gender_was,:to => :person,:allow_nil => true
enum gender: { male: "male",female: "female" }
end
end
居民有这种担忧。
现在,当我这样做时:
2.6.6> Resident.last.gender
Resident Load (16.2ms) SELECT "residents".* FROM "residents" ORDER BY "residents"."id" DESC LIMIT $1 [["LIMIT",1]]
Person Load (16.1ms) SELECT "people".* FROM "people" WHERE "people"."id" = $1 LIMIT $2 [["id",48],["LIMIT",1]]
=> "male"
但是当我问:男性?时,我得到了
2.6.6> Resident.last.male?
Resident Load (17.0ms) SELECT "residents".* FROM "residents" ORDER BY "residents"."id" DESC LIMIT $1 [["LIMIT",1]]
=> false
这怎么可能?
如果我在Person模型中包括该枚举,则可以正常工作:
Person.last.male?
Person Load (15.9ms) SELECT "people".* FROM "people" ORDER BY "people"."id" DESC LIMIT $1 [["LIMIT",1]]
=> true
我创建了一个简单的演示应用程序来演示此行为: https://github.com/rept/enum_app
r = Resident.create(gender: :male,local_gender: :local_male)
r.local_male?
=> true
r.male?
=> false
解决方法
声明一个枚举属性,其中值映射到 数据库,但可以按名称查询。
-ActiveRecord::Enum
您需要在枚举中使用整数列,或显式声明映射。 Rails假定数据库中存储的值等于传递给enum
的数组的索引。由于"male" != 0
#male?
将返回false。
module Nobi::Personable
extend ActiveSupport::Concern
included do
belongs_to :person,:autosave => true
enum gender: {
male: "male",female: "female"
}
end
end
虽然使用字符串列会失败,但首先要使用枚举来明确声明映射被视为最佳实践,因为这将避免调试仅通过重新排序枚举值可能导致的破损。数组。
如果您需要证明:
class User < ApplicationRecord
enum gender: [:male,:female] # users.gender is an integer column
end
irb(main):003:0> User.first
(0.9ms) SELECT sqlite_version(*)
User Load (2.0ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT",1]]
=> #<User id: 9,created_at: "2020-10-29 09:24:12",updated_at: "2020-10-29 09:24:12",gender: "male">
irb(main):004:0> User.first.male?
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT",1]]
=> true
class Resident < ApplicationRecord
# residents.gender is a string column
enum gender: {
male: 'male',female: 'female'
}
end
irb(main):001:0> Resident.create!(gender: 'male')
(0.4ms) SELECT sqlite_version(*)
(0.1ms) begin transaction
Resident Create (1.6ms) INSERT INTO "residents" ("gender","created_at","updated_at") VALUES (?,?,?) [["gender","male"],["created_at","2020-10-29 09:56:59.471917"],["updated_at","2020-10-29 09:56:59.471917"]]
(4.7ms) commit transaction
=> #<Resident id: 1,gender: "male",created_at: "2020-10-29 09:56:59",updated_at: "2020-10-29 09:56:59">
irb(main):002:0> Resident.first.male?
Resident Load (0.2ms) SELECT "residents".* FROM "residents" ORDER BY "residents"."id" ASC LIMIT ? [["LIMIT",1]]
=> true