【问题标题】:How to coerce type of ActiveRecord attribute returned by :select phrase on joined table?如何强制:连接表上的选择短语返回的 ActiveRecord 属性类型?
【发布时间】:2011-02-11 06:48:59
【问题描述】:

AR 2.3.5 遇到问题,例如:

users = User.all( :select => "u.id, c.user_id", :from => "users u, connections c",
       :conditions => ... )

返回,例如:

=> [#<User id: 1000>]
>> users.first.attributes
=> {"id"=>1000, "user_id"=>"1000"}

请注意,AR 将搜索到的模型的 id 返回为数字,但将连接模型的选定 user_id 返回为 String,尽管两者在数据库架构中都是 int(11)

我怎样才能更好地形成这种类型的查询来选择支持多个模型的表列并检索它们的自然类型而不是 String ?似乎 AR 在某个地方对此进行了抨击。我如何在 AR 加载时强制返回类型,而不必在每个事后访问中添加 .to_i (等)?

【问题讨论】:

  • 你能解释一下什么是“连接”,它与用户有什么关系?

标签: ruby-on-rails activerecord select join type-coercion


【解决方案1】:

不幸的是,这不会很容易发生。来自 DB 连接的所有数据都以字符串形式传入 rails,类型的转换发生在 rails 在运行时创建的每个动态属性方法中。它通过应用程序启动时检索的表的列类型元数据知道哪些属性要转换为哪种类型。每个模型只有它自己的列的列元数据,这就是它自己的列最终具有正确类型的原因。没有简单的方法可以自动转换为正确的类型。

另一方面,您可以创建一个简单的转换方法,该方法将采用 Hash 并自动转换属性。

类似这样的:

users = User.all(:select => "cl, comments.c2", ...)
users = convert_columns(users, 'c2' => :integer, 'other_column' => :date)

def convert_columns(records, columns = {})
  records.each do |rec|
    columns.each do |col, type|
      rec[col] = case type
         when :int then rec[col].to_i
         when :date then ........
         ....
      end
    end
  end
end

【讨论】:

    【解决方案2】:

    为什么在 User.method 中使用 :from => "users" ? 以下将进行内部连接(无论如何,这就是您正在做的事情)

    users = User.all(:include => :connections, :select => "users.id, connections.user_id", :conditions => {...})
    

    这将是对数据库的非常繁重的查询。 更快的查询将使用外部连接。

    这也会将键返回为 INT 而不是 STRING

    一个更快的选择是

    Connection.all(:include => :user, :conditions => {...}).collect {|e| [e.user_id, e.id] }
    

    这为您提供了一个带有 id 的数组。如果您只选择“id, user_id”列,那么它可能不一定是 AR 对象。数组可以更快。

    我希望我在这里没有遗漏一些要点。建议我,如果我是的话。

    【讨论】:

    • from: 被包含为表列名称的别名。动态混合了一些子条件。我会考虑你的方法并用它做一些测试——谢谢。
    【解决方案3】:

    如果您想要快速解决方案 - 尝试使用 after_find 回调并在那里预设正确的属性类型:

    class User < ActiveRecord::Base
    
      after_find :preset_types
    
    
      private
      def preset_types user
        user.user_id = user.user_id.to_i
      end
    
    end
    

    【讨论】:

      猜你喜欢
      • 2020-11-01
      • 2019-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-22
      • 2020-09-14
      • 1970-01-01
      相关资源
      最近更新 更多