2012-01-11 2 views
2

Работа с устаревшей базой данных, я столкнулся с столбцом в базе данных SQL Server, где дата хранится как десятичная. Например. 2011-04-23 хранится как 20110423.0.Работа с преобразованиями столбцов в Ruby ActiveRecord

Есть ли общий механизм ActiveRecord для работы со «странными» соглашениями о хранении столбцов? Enum-подобные столбцы, где они фактически хранятся как целые числа, - это еще один случай, который может также использовать тот же механизм, но я не могу найти то, что ищу.

Похоже сериализации получает меня отчасти есть:

class Thing < ActiveRecord::Base 
    class DecimalDate 
    def load(date) 
     if date.is_a? Numeric 
     y,m,d = /^(\d\d\d\d)(\d\d)(\d\d)/.match(date.to_s)[1..3].map(&:to_i) 
     Date.civil(y,m,d) 
     end 
    end 
    def dump(date) 
     date ? date.strftime('%Y%m%d').to_i : 0 
    end 
    end 
    serialize :weird_date, DecimalDate 
end 

rails c 
> Thing.first.weird_date 
=> Sun, 02 Jan 2011 

Но иллюзия тонкая. Столбец не «знает», что это дата, хранящаяся как десятичная. Например. сравнение не выполнено:

rails c 
> Thing.where('weird_date > ?', 1.week.ago) 
... 
ActiveRecord::StatementInvalid: ... Error converting data type varchar to numeric.: 
+0

Можете ли вы перенести данные на соглашение, поддерживаемое Rails? Или вы вынуждены иметь дело с этим? – basgys

+0

Можете ли вы скрыть все обращения к 'weird_date' внутри вашей вещи? Это по крайней мере локализует странность. –

+0

@basgys: к сожалению, вынужден иметь дело с этим. – benizi

ответ

0

Если вы вынуждены иметь дело с устаревшими данными, я вижу две возможности управлять им.

1 Из базы данных

Вы можете «конвертировать» Ваши данные, делая вид вашей таблицы, конвертировать (дата) поля на лету. Затем вы создаете триггер (перед вставкой/обновлением) на этом представлении, который преобразует ваши данные обратно в старый формат. Наконец, вы указываете ActiveRecord использовать свой вид вместо своей таблицы.

2 из приложения (Rails)

Найти способ сказать ActiveRecord, чтобы сделать ту же работу. Вы уже пытались управлять им с обратными вызовами AR с помощью after_initialize и before_save? Дополнительная информация here