我有一个表,其中包含一个基于整数的列(状态(,我将其用于Rails模型中的枚举属性。
在做的时候:
Post.select(:id, ..., :status)
定义为:
enum status: { inactive: 0, active: 1, ... }
它按预期返回所有内容,但状态列在其字符串值中返回为非活动、活动等。但我需要它作为整数。
我怎样才能得到它?
我目前只是使用ActiveRecord::Base.connection.execute
并传递原始查询:
ActiveRecord::Base.connection.execute('select id, ..., status from posts')
你试过这个吗?
# Rails < 5
post = Post.find(123)
post.read_attribute(:status)
# Rails >= 5
post = Post.find(123)
post.read_attribute_before_type_cast(:status)
这不会是最优雅的方式,但这是我看到的唯一方法,无需循环访问您的对象。
您可以通过创建 2 个这样的类来实现这一点:
class Post < ApplicationRecord
end
另一个:
class PostSave < Post
enum status: { inactive: 0, active: 1, ... }
end
当你使用Post
类时,你不会得到"status"列enum
值,但是当你使用PostSave
类时,你可以像你已经在使用的那样使用你的enum
。
现在当你这样做时
Post.select(:id, :status)
它会根据需要为您提供"状态"列的整数值。
是的。这就是枚举字段在 Rails 中的工作方式。数据存储为整数,但显示为字符串 - 基于 enum 中定义的内容: https://api.rubyonrails.org/v5.2.3/classes/ActiveRecord/Enum.html
如果您真的想获得整数,请尝试以下方法之一:
- 删除枚举声明。数据存储为整数。没有该行查询将返回整数
- 这不是最漂亮的代码,但是:
Post.statuses[post.status]
会起作用
你可以试一试:
Post.select(:id, ..., 'status as int_status')
我不确定这是否直接适用,因为我不知道 Rails 或您的确切要求。但是您表示希望"从数据库获取记录集合";所以也许会。
Postgres 包含 2 个表,您需要联接这些表才能获取枚举的集合值pg_catalog:pg_type和pg_enum如下所示(其中ENUM_NAME替换为相应的枚举类型名称:
select t.typname,e.enumsortorder, e.enumlabel
from pg_type t
join pg_enum e
on (t.oid = e.enumtypid)
where t.typname = 'ENUM_NAME'
order by e.enumsortorder;
我注意到的一个区别是,在 Postgres 中,关联的数值被定义为 Real,而不是整数。这是由于这些值的实际维护方式。例:
create type t_ord_stat as enum ('Ordered', 'Delivered', 'Billed', 'Complete', 'Canceled');
select e.enumsortorder, e.enumlabel
from pg_type t
join pg_enum e
on (t.oid = e.enumtypid)
where t.typname = 't_ord_stat'
order by e.enumsortorder;
alter type t_ord_stat add value 'Suppended: Out-of-Stock' after 'Ordered';
alter type t_ord_stat add value 'Suppended: Credit Check' before 'Suppended: Out-of-Stock' ;
alter type t_ord_stat add value 'Suppended: Customer Refused Delivery' before 'Billed';
select e.enumsortorder, e.enumlabel
from pg_type t
join pg_enum e
on (t.oid = e.enumtypid)
where t.typname = 't_ord_stat'
order by e.enumsortorder;
上面给出了枚举字符串值背后的实际数值(因为列名表明它用于排序目的(。您可以使用以下公式获得相对整数值
select row_number() over() relative_seq, en.enumlabel
from (select e.enumsortorder, e.enumlabel
from pg_type t
join pg_enum e
on (t.oid = e.enumtypid)
where t.typname = 't_ord_stat'
order by e.enumsortorder) en;
我将把实际转换为 Rails 的工作留给你。希望对您有所帮助。
您可以将 SQL 语句中的列映射到另一个字段并从那里读取它,这样 Rails 直接传递值,因为它不知道它是一个枚举(它根本不知道列(:
Post.select('id, title, status, status AS status_int').each do |post|
puts post.status # 'inactive'
puts post.status_int # 0
end
如果你必须有相同的列名,那么你就不走运了,除非你做更多的工作:
class Post
STATUSES = %w(inactive active)
end
Post.all.each do |post|
index = Post::STATUSES.index(post.status)
# use 'index' here instead of `post.status`
end
如果这些都不够,那么这听起来肯定像是 http://xyproblem.info/......因为这些答案应该适用于 99% 的情况。所以你应该解释为什么你不能在处理对象时只使用status_int
,或者为什么你不能将 int 存储在变量中,或者......为什么你需要访问整数,这违背了枚举的目的。
上述解决方案正在工作。我已经尝试在mysql版本5.7.28上使用原始sql。 以下查询仅适用于 MySQL。
我仍在寻找帖子查询,我会尽快通知您。
创建表帖子(id 整数,标题 varchar(100(,状态枚举("活动","非活动"(不为空(; 插入到帖子(ID,标题,状态(值(1,"您好","非活动"( 从帖子中选择标题、状态+0;