如何透明地修改模型中的ActiveRecord方法?

时间:2010-02-08 19:10:03

标签: ruby-on-rails activerecord

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

什么是'正确'的方式?

2 个答案:

答案 0 :(得分:7)

你覆盖了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列,因为您正在向DB发送原始字节。像这样的迁移:

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

答案 1 :(得分:1)

我查看了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 }
}

另请注意:二进制文件不是您想要的,因为它会创建一个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来添加列类型。