在ActiveRecord对象中获取属性的类型


70

我想知道是否有可能以编程方式获取类型(如AR所知-例如在迁移脚本和数据库中)(我知道数据存在于某处)。

例如,我可以处理所有属性名称:

ar.attribute_names.each { |name| puts name }

.attributes仅返回名称到其当前值的映射(例如,如果未设置该字段,则没有类型信息)。

我在一些地方看到了类型信息:

在脚本/控制台中,输入AR实体的名称:

>> Driver
=> Driver(id: integer, name: string, created_at: datetime, updated_at: datetime)

所以很清楚它知道类型。另外,还有.column_for_attribute,它具有一个attr名称并返回一个列对象-该类型具有埋在基础数据库列对象中的类型,但似乎并不是一种干净的方式来获取它。

我也想知道是否有一种方法可以使新的“ ActiveModel”友好(rails3)并且与数据库详细信息分离(但是类型信息可能不是它的一部分,我似乎无法找出是不是)。

谢谢。

Answers:


106

在Rails 3中,需要使用模型“ Driver” Driver.columns_hash

Driver.columns_hash["name"].type  #returns :string

如果要遍历它们,可以执行以下操作:

Driver.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}

将输出以下内容:

id => integer
name => string
created_at => datetime
updated_at => datetime

您知道我如何测试值是否与列匹配,类似这样2.is_a? Driver.columns_hash["name"].type
mariowise 2014年

这不适用于Rails 5+中的虚拟属性
estani

27

在Rails 5中,您可以独立于数据库执行此操作。如果您使用新的Attributes API定义(其他)属性,则这一点很重要。

从模型类获取所有属性:

pry> User.attribute_names
=> ["id",
 "firstname",
 "lastname",
 "created_at",
 "updated_at",
 "email",...

获取类型:

pry> User.type_for_attribute('email')
=> #<ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString:0x007ffbab107698
 @limit=255,
 @precision=nil,
 @scale=nil>

有时,这比需要的信息更多。有一个便捷功能,可将所有这些类型映射到一个核心集(:integer,:string等)。

> User.type_for_attribute('email').type
=> :string 

您还可以使用attribute_types在一次调用中获得所有数据,该属性返回'name': type哈希值。


3
这也适用于Rails 4.2。重要的是要注意,type_for_attribute('id')只需要一个字符串。这有点令人困惑,因为它type_for_attribute('id').type返回一个符号。
xander-miller

1
如果“独立于数据库”是指ORM,则Mongoid尚未实现type_for_attribute。也许在Rails 5正式发布之后。
西里尔·杜松-多丽丝

22

您可以通过执行以下操作访问列的类型:

#script/console
Driver.columns.each {|c| puts c.type}

如果要获取特定模型中所有列类型的列表,可以执行以下操作:

Driver.columns.map(&:type) #gets them all
Driver.columns.map(&:type).uniq #gets the unique ones

谢谢。我猜这不会成为ActiveModel的一部分,因为它绑定到了列(可能不会成为AM)。但这对于AR来说确实很棒。您知道我实际上已经知道了这一点,但是出于某种原因将其阻止了。
Michael Neale 2010年

7

在rails 5中,这将为您提供所有字段名称及其数据类型的列表:

Model_Name.attribute_names.each do |k| puts "#{k} = #{Model_Name.type_for_attribute(k).type}" end

注意type_for_attribute需要字符串。它很高兴接受符号或不存在的名称,并返回不进行强制转换的ActiveModel :: Type :: Value!IMO一个错误,我将尝试报告/修复。
贝尼·切尔尼亚夫斯基-帕斯金

3

此代码段将为您提供模型的所有属性以及哈希中关联的数据库数据类型。只需用您的Active Record模型替换Post。

Post.attribute_names.map {|n| [n.to_sym,Post.type_for_attribute(n).type]}.to_h

将返回这样的哈希值。

=> {:id=>:integer, :title=>:string, :body=>:text, :created_at=>:datetime, :updated_at=>:datetime, :topic_id=>:integer, :user_id=>:integer} 

3

Rails 5+(也适用于虚拟属性):

Model.attribute_types['some_attribute'].type

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.