【问题标题】:Getting types of the attributes in an ActiveRecord object获取 ActiveRecord 对象中的属性类型
【发布时间】:2011-01-24 20:49:03
【问题描述】:

我想知道是否有可能以编程方式获取类型(如 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,它接受一个属性名称并返回一个列对象——它的类型隐藏在底层数据库列对象中,但它似乎不是一个干净的获取它的方法。

如果有一种方法对即将到来的新“ActiveModel”(rails3)友好并且与数据库细节分离(但也许类型信息不会是其中的一部分,我可以),我也会感兴趣t似乎找出是否是)。

谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord activemodel


    【解决方案1】:

    您可以通过以下方式访问列的类型:

    #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 来说太棒了。你知道我其实心里早就知道了,但由于某种原因把它屏蔽了。
    【解决方案2】:

    在 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
    • 这不适用于 rails 5+ 中的虚拟属性
    【解决方案3】:

    在 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 
    

    您还可以使用返回'name': type 哈希的attribute_types 在一次调用中获取所有数据。

    【讨论】:

    • 这也适用于 Rails 4.2。需要注意的是,type_for_attribute('id') 只接受一个字符串。这有点令人困惑,因为type_for_attribute('id').type 返回一个符号。
    • 如果数据库独立你的意思是 ORM,那么 Mongoid 还没有实现这个type_for_attribute。也许在 Rails 5 正式发布之后。
    【解决方案4】:

    这个 sn-p 将为您提供模型的所有属性以及哈希中的关联数据库数据类型。只需将 Post 替换为您的 Active Record 模型即可。

    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} 
    

    【讨论】:

      【解决方案5】:

      在 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 一个错误,我会尝试报告/修复。
      【解决方案6】:

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

      Model.attribute_types['some_attribute'].type
      

      【讨论】:

        【解决方案7】:

        在 Rails 4 中,您将使用 Model.column_types

        【讨论】:

          【解决方案8】:

          假设 Foobar 是您的 Active Record 模型。你也可以这样做:

          attributes = Foobar.attribute_names.each_with_object({}) do |attribute_name, hash|
            hash[attribute_name.to_sym] = Foobar.type_for_attribute(attribute_name).type
          end
          

          也适用于 Rails 4

          【讨论】:

            猜你喜欢
            • 2019-09-19
            • 1970-01-01
            • 2023-03-28
            • 1970-01-01
            • 2011-02-20
            • 2020-03-17
            • 1970-01-01
            • 1970-01-01
            • 2021-03-18
            相关资源
            最近更新 更多