Ruby on rails 如何在模型中透明地修改ActiveRecord方法?

Ruby on rails 如何在模型中透明地修改ActiveRecord方法?,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,我有一个模型,UUID存储在MySQL表的二进制(16)字段中。我希望能够透明地将setter方法的十六进制uuid转换为二进制,并在使用getter方法时返回 “正确”的方法是什么 我查看了ActiveRecord2.3.5(mysql_adapter.rb)的源代码。查看本机\u数据库\u类型散列可以清楚地看出,它不支持二进制(16)数据类型: NATIVE_DATABASE_TYPES = { :primary_key => "int(11) DEFAULT NULL auto_

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


“正确”的方法是什么

我查看了ActiveRecord2.3.5(mysql_adapter.rb)的源代码。查看本机\u数据库\u类型散列可以清楚地看出,它不支持二进制(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 }
}
还要注意:二进制不是您想要的,因为这样会创建一个BLOB列

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

更新:经过一些搜索,Matthew Higgins的以下博客文章似乎很有希望(“虽然在迁移中可以执行任意SQL语句,但另一种选择是扩展MySql适配器以支持新类型的列。”):


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

您可以覆盖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

在每个模型或每个字段的基础上重写getter和setter并不像教ActiveRecord如何处理二进制(16)那样优雅。将add_列与:BINARY一起使用不会给出二进制类型。我还尝试了上面的代码示例,遇到了一些问题。首先,我想你指的是pack(“C*),而不是pack(C*)。但更一般地说,如果可能的话,我会让MySQL处理二进制(16)类型之间的转换,而不是在Ruby中进行转换。根据Aaron Scrugs对“HEX()和UNHEX()函数允许您在二进制数据和应用程序友好的十六进制字符串之间进行转换”的评论(#11),这是怎么回事?使用上面的迁移,您将获得真正的二进制列。我修复了语法错误。下面的答案和注释有帮助吗?你找到适合你的东西了吗?
class AddUuidToUsers
  def self.up
    execute "ALTER TABLE users ADD uuid BINARY(16)"
  end
end