在 Rails 上保留数据并覆盖 Getter/Setter
Preserving Data on Rails Migration with Override on Getter/Setter
我正在进行迁移,我需要 (a) 更改列的数据类型并 (b) 保留该列中的数据(即,将其转换为新数据类型并将其保留在同一列中)。新列类型要求我覆盖 getters 和 setters,这会导致迁移失败。
有一个用户 table,其中包含用户连接的 IP 地址字段:ip_addr
。这目前是一个字符串,我想将其更改为整数。迁移的 up
方法如下所示:
def up
add_column :users, :curip, :integer
User.reset_column_information
User.all.each do |u|
u.update_attribute :curip, User.ip_str_to_int(u.ip_addr)
end
remove_column :users, :ip_addr
rename_column :users, :curip, :ip_addr
end
(User.ip_str_to_int
计算将 IP 地址四边形转换为整数。)
我还有一些方法可以覆盖 ip_addr
的 getter 和 setter 以调用 User.ip_str_to_int
和相应的方法 User.ip_int_to_str
。这些方法看起来像这样:
def ip_addr
val = read_attribute(:ip_addr)
User.ip_int_to_str(val)
end
def ip_addr=(val)
write_attribute(:ip_addr, User.ip_str_to_int(val))
end
现在你可能已经猜到问题所在了。当迁移 运行s 时,它会阻塞,因为重写的 getter/setters 期望该列包含一个整数,但在迁移发生时,该列实际上包含一个字符串。我已经分别测试了 migration 和 getter/setter 方法,它们都很好。对于我自己的开发环境,我可以简单地注释掉 getters/setters 到 运行 的迁移,然后将它们放回去。但这是一个问题,不适用于生产。
有什么建议吗?我知道如果我不尝试保留相同的列名就不会遇到这个问题,但更改列名意味着更改其他代码。
环境:sqlite 3; Ruby2.1.4; Rails 3.2.13.
您可以修改 getter 方法来处理数据是字符串的情况...
def ip_addr
val = read_attribute(:ip_addr)
return val if val.is_a? String
User.ip_int_to_str(val)
end
我正在进行迁移,我需要 (a) 更改列的数据类型并 (b) 保留该列中的数据(即,将其转换为新数据类型并将其保留在同一列中)。新列类型要求我覆盖 getters 和 setters,这会导致迁移失败。
有一个用户 table,其中包含用户连接的 IP 地址字段:ip_addr
。这目前是一个字符串,我想将其更改为整数。迁移的 up
方法如下所示:
def up
add_column :users, :curip, :integer
User.reset_column_information
User.all.each do |u|
u.update_attribute :curip, User.ip_str_to_int(u.ip_addr)
end
remove_column :users, :ip_addr
rename_column :users, :curip, :ip_addr
end
(User.ip_str_to_int
计算将 IP 地址四边形转换为整数。)
我还有一些方法可以覆盖 ip_addr
的 getter 和 setter 以调用 User.ip_str_to_int
和相应的方法 User.ip_int_to_str
。这些方法看起来像这样:
def ip_addr
val = read_attribute(:ip_addr)
User.ip_int_to_str(val)
end
def ip_addr=(val)
write_attribute(:ip_addr, User.ip_str_to_int(val))
end
现在你可能已经猜到问题所在了。当迁移 运行s 时,它会阻塞,因为重写的 getter/setters 期望该列包含一个整数,但在迁移发生时,该列实际上包含一个字符串。我已经分别测试了 migration 和 getter/setter 方法,它们都很好。对于我自己的开发环境,我可以简单地注释掉 getters/setters 到 运行 的迁移,然后将它们放回去。但这是一个问题,不适用于生产。
有什么建议吗?我知道如果我不尝试保留相同的列名就不会遇到这个问题,但更改列名意味着更改其他代码。
环境:sqlite 3; Ruby2.1.4; Rails 3.2.13.
您可以修改 getter 方法来处理数据是字符串的情况...
def ip_addr
val = read_attribute(:ip_addr)
return val if val.is_a? String
User.ip_int_to_str(val)
end