Rails 枚举返回整数值,而不是字符串表示形式



我有一个表,其中包含一个基于整数的列(状态(,我将其用于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

如果您真的想获得整数,请尝试以下方法之一:

  1. 删除枚举声明。数据存储为整数。没有该行查询将返回整数
  2. 这不是最漂亮的代码,但是: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;

相关内容

  • 没有找到相关文章

最新更新