Convert data when putting them into a database using active record
What's the cleanest way to convert data (field values) when storing/loading into/from a database.
I usually convert the values the user has entered in the model class:
def date_str
format_date(开发者_运维知识库self.date)
end
def date_str=(str)
self.date = DateParser.parse(str)
end
(Note: The internal date parser is not sufficient, it doesn't cover many of our locale date notation styles, anyway).
This works already pretty fine, but I doesn't let me check for validity the usual RoR way because we don't store the string the user has entered. I usually let the parser function return nil if anything was wrong with the date, but this isnt very user-friendly – I cant really tell if the user hasn't entered anything or just a invalid value.
I'm looking for some way to integrate the conversion better into the A::R world where I can produce some useful error message if the conversion fails. Best would be if I could use the same facilities as the A::R::Adapter uses internally.
Has anybody some good ideas? What are other approaches?
The way you've suggested is fine, another alternative would be to do something like
attr_accessor :when
before_validation :update_date
def update_date
self.date = parse_date(self.when) if self.when
end
def parse_date(date_as_string)
# do something with the date
end
However, you're going to have write the validation yourself. It's not ideal, but it shouldn't be that much code.
If you're planning on using this all over your app, you should maybe look at writing a custom validator too, you can get more info about that here:
http://marklunds.com/articles/one/312
You can do this in a before validation callback that way you can use the normal AR validations on date.
before_validation :convert_date
def convert_date
self.date = DateParser.parse(self[:date])
end
The attribute_normalizer provides a nice dsl for doing this kind of thing like this:
class Klass < ActiveRecord::Base
normalize_attributes :date do |value|
value.is_a?(String) ? DateParser.parse(value) : nil
end
end
精彩评论