Rails 枚举 return 整数值,不是字符串表示
Rails Enum return integer value, not string representation
我有一个 table,其中包含一个基于整数的列(状态),我将其用于 Rails 模型中的枚举属性。
正在做的事情:
Post.select(:id, ..., :status)
定义为:
enum status: { inactive: 0, active: 1, ... }
它 returns 一切如预期,但状态列在其字符串值中返回为 inactive、active,等。但我需要它作为一个整数。
我怎样才能得到它?
我目前正在使用 ActiveRecord::Base.connection.execute
并传递原始查询:
ActiveRecord::Base.connection.execute('select id, ..., status from posts')
是的。这就是枚举字段在 Rails 中的工作方式。数据存储为整数,但显示为字符串 - 基于枚举中定义的内容:
https://api.rubyonrails.org/v5.2.3/classes/ActiveRecord/Enum.html
如果您真的想获得整数,请尝试以下方法之一:
- 删除枚举声明。数据存储为整数。如果没有该行,查询将 return Integer
- 这不是最漂亮的代码,但是:
Post.statuses[post.status]
可以工作
你试过吗?
# Rails < 5
post = Post.find(123)
post.read_attribute(:status)
# Rails >= 5
post = Post.find(123)
post.read_attribute_before_type_cast(:status)
以上解决方案有效。我在 mysql 版本 5.7.28 上尝试使用原始 sql。
以下查询仅适用于 mysql。
我仍在寻找有关 postgres 的查询,我会尽快通知您。
create table Posts(id integer, title varchar(100), status ENUM ('active', 'inactive') NOT NULL);
insert into Posts(id, title, status) values(1, "Hello", 'inactive')
select title, status+0 from Posts;
你可以试一试:
Post.select(:id, ..., 'status as int_status')
我不确定这是否直接适用,因为我不知道 Rails 或您的具体要求。但是你表示希望 "get a collection of records from the DB";所以也许会。
Postgres 在 pg_catalog 中包含 2 个表,您需要加入以获取枚举的集合值: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 中,关联的数值被定义为实数,而不是整数。这是由于值的实际维护方式。示例:
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 存储在变量中,或者......为什么您根本需要访问整数,这会失败枚举的目的。
这不是最优雅的方式,但这是我认为无需遍历对象的唯一方式。
您可以像这样创建 2 个 classes 来实现此目的:
class Post < ApplicationRecord
end
另一个:
class PostSave < Post
enum status: { inactive: 0, active: 1, ... }
end
当您使用 Post
class 时,您不会获得 "status" 列的 enum
值,但是当您使用 PostSave
class 您可以像以前一样使用 enum
。
现在当你
Post.select(:id, :status)
它将根据需要为 "status" 列提供整数值。
我有一个 table,其中包含一个基于整数的列(状态),我将其用于 Rails 模型中的枚举属性。
正在做的事情:
Post.select(:id, ..., :status)
定义为:
enum status: { inactive: 0, active: 1, ... }
它 returns 一切如预期,但状态列在其字符串值中返回为 inactive、active,等。但我需要它作为一个整数。
我怎样才能得到它?
我目前正在使用 ActiveRecord::Base.connection.execute
并传递原始查询:
ActiveRecord::Base.connection.execute('select id, ..., status from posts')
是的。这就是枚举字段在 Rails 中的工作方式。数据存储为整数,但显示为字符串 - 基于枚举中定义的内容: https://api.rubyonrails.org/v5.2.3/classes/ActiveRecord/Enum.html
如果您真的想获得整数,请尝试以下方法之一:
- 删除枚举声明。数据存储为整数。如果没有该行,查询将 return Integer
- 这不是最漂亮的代码,但是:
Post.statuses[post.status]
可以工作
你试过吗?
# Rails < 5
post = Post.find(123)
post.read_attribute(:status)
# Rails >= 5
post = Post.find(123)
post.read_attribute_before_type_cast(:status)
以上解决方案有效。我在 mysql 版本 5.7.28 上尝试使用原始 sql。 以下查询仅适用于 mysql。
我仍在寻找有关 postgres 的查询,我会尽快通知您。
create table Posts(id integer, title varchar(100), status ENUM ('active', 'inactive') NOT NULL); insert into Posts(id, title, status) values(1, "Hello", 'inactive') select title, status+0 from Posts;
你可以试一试:
Post.select(:id, ..., 'status as int_status')
我不确定这是否直接适用,因为我不知道 Rails 或您的具体要求。但是你表示希望 "get a collection of records from the DB";所以也许会。
Postgres 在 pg_catalog 中包含 2 个表,您需要加入以获取枚举的集合值: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 中,关联的数值被定义为实数,而不是整数。这是由于值的实际维护方式。示例:
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 存储在变量中,或者......为什么您根本需要访问整数,这会失败枚举的目的。
这不是最优雅的方式,但这是我认为无需遍历对象的唯一方式。
您可以像这样创建 2 个 classes 来实现此目的:
class Post < ApplicationRecord
end
另一个:
class PostSave < Post
enum status: { inactive: 0, active: 1, ... }
end
当您使用 Post
class 时,您不会获得 "status" 列的 enum
值,但是当您使用 PostSave
class 您可以像以前一样使用 enum
。
现在当你
Post.select(:id, :status)
它将根据需要为 "status" 列提供整数值。