【问题标题】:How can I transparently modify an ActiveRecord method in a model?如何透明地修改模型中的 ActiveRecord 方法?
【发布时间】:2010-02-08 19:10:02
【问题描述】:

我有一个模型,其 UUID 存储在 MySQL 表的 BINARY(16) 字段中。我希望能够透明地将十六进制 uuid 转换为 setter 方法的二进制,并在我使用 getter 方法时转换回来。

什么是“正确”的进行方式?

【问题讨论】:

  • 下面的答案和 cmets 有帮助吗?你找到适合你的东西了吗?

标签: ruby-on-rails activerecord


【解决方案1】:

你覆盖了 setter 和 getter:

class User < ActiveRecord::Base
  def uuid=(value)
    @uuid = write_attribute(:uuid, value.scan(/../).map {|n| n.to_i(16)}.pack("C*"))
  end

  def uuid
    @uuid ||= read_attribute(:uuid).unpack("C*").map {|n| sprintf("%02x", n)}.join
  end
end

当然,您需要一个 BINARY 列,因为您将原始字节发送到数据库。像这样的迁移:

class AddUuidToUsers
  def self.up
    execute "ALTER TABLE users ADD uuid BINARY(16)"
  end
end

【讨论】:

  • 在每个模型或每个字段的基础上覆盖 getter 和 setter 并不像教 ActiveRecord 如何处理 BINARY(16) 那样优雅。
  • 将 add_column 与 :binary 一起使用不会给出 BINARY 类型。它将给出一个 BLOB 类型。
  • 我也尝试了上面的代码示例,但遇到了一些问题。首先,我认为您的意思是 pack("C*") 而不是 pack(C*)。但更一般地说,如果可能的话,我会让 MySQL 处理与 BINARY(16) 类型之间的转换,而不是在 Ruby 中进行。根据 Aaron Scrugs 在code.openark.org/blog/mysql/… 上的评论 (#11),“HEX() 和 UNHEX() 函数允许您在二进制数据和应用程序友好的十六进制字符串之间进行转换。”
  • 怎么样?您将使用上面的迁移获得真正的 BINARY 列。我修复了语法错误。
【解决方案2】:

我查看了 ActiveRecord 2.3.5 (mysql_adapter.rb) 的源代码。查看 NATIVE_DATABASE_TYPES 哈希可以清楚地表明它不支持 BINARY(16) 数据类型:

NATIVE_DATABASE_TYPES = {
  :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
  :string      => { :name => "varchar", :limit => 255 },
  :text        => { :name => "text" },
  :integer     => { :name => "int", :limit => 4 },
  :float       => { :name => "float" },
  :decimal     => { :name => "decimal" },
  :datetime    => { :name => "datetime" },
  :timestamp   => { :name => "datetime" },
  :time        => { :name => "time" },
  :date        => { :name => "date" },
  :binary      => { :name => "blob" },
  :boolean     => { :name => "tinyint", :limit => 1 }
}

还要注意 :binary 不是您想要的,因为这会创建一个 BLOB 列。

如果您愿意,我建议您扩展 ActiveRecord 以支持 BINARY(16) 类型。

更新:在 Matthew Higgins 的以下博客文章中进行了一些搜索后,似乎很有希望(“虽然可以在迁移中执行任意 SQL 语句,但另一种方法是扩展 MySql 适配器以支持新类型的列。”): http://www.strictlyuntyped.com/2008/07/mysql-lovin-part-2-adding-new-column.html

如果你能做到这一点,我希望你能分享你的想法。和 Matthew 一样,我希望 ActiveRecord 有一个更简洁的 API 来添加列类型。

【讨论】:

    猜你喜欢
    • 2014-03-17
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多