The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Завершение саги о датах

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Maxim Kulkin

Posts: 58
Nickname: hapk
Registered: Sep, 2006

Maxim Kulkin is developer in Selectosa Systems.
Завершение саги о датах Posted: Jul 4, 2007 3:32 PM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Maxim Kulkin.
Original Post: Завершение саги о датах
Feed Title: Software development
Feed URL: http://maximkulkin.blogspot.com/feeds/posts/full?alt=rss
Feed Description: Software development
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Maxim Kulkin
Latest Posts From Software development

Advertisement

Никак не мог успокоиться: все решения, которые я находил, не содержали решения для выдачи ошибок, если дату невозможно распарсить. Чаще всего, если попытка перевода строки в дату не была успешной, вместо даты - nil и никаких тебе ошибок.

Наконец мне удалось сложить все кусочки воедино и получить достаточно неплохое, на мой взгляд, решение.

1. Как редактировать.
Как уже обсуждалось в моих предыдущих постах, самое правильное при редактировании даты - отказаться от трех списков и оставить только одно текстовое поле, куда можно вводить строковое представление даты в определенном формате. Плюс можно прикрутить жаваскриптовый календарик к этому текстовому полю.
Как же высветить введенное значение, если распарсить строку не удалось ? Вспоминаем, что для этого есть *_before_type_cast атрибуты. Напомню: когда мы присваиваем значения конкретному атрибуту, это значение сохраняется внутри экземпляра модели нетронутым (про многопараметровые значения мы не говорим). Конвертация же происходит, когда мы пытаемся получить значение атрибута экзепляра класса модели, а *_before_type_cast возвращает значение, обходя конвертацию. Поэтому, надо только сделать date_select хэлпер, который будет пытаться сконвертировать значение атрибута (сконвертированное, т.е. типа Date) в строку, если это значение не nil, иначе - выкладывать строковое представление значение *_before_type_cast. Плюс код для яваскриптового календарика (например, этого).
Отлично, теперь можно вводить даты в стандартных форматах (например, YYYY-MM-DD) и не терять введенное значение, если преобразовать его в дату не удастся.

2. Нужные форматы даты.
В моем приложении просто необходимо, чтобы дату можно было вводить в русском формате (т.е. DD.MM.YYYY). Поэтому, надо как-то научить дату понимать такой формат.
Поизучав исходники, я пришел к тому, что конвертация из строки в дату производится экземпляром объекта, который представляет соответствующий столбец базы данных. По реализации становится ясно, что конвертация осуществляется методом ParseDate#parsedate стандартной библиотеки Ruby. Недолго думая, расширяем этот метод, чтобы он понимал нужный нам формат даты:
ParseDate.class_eval do
class << self
def parsedate_with_ru_format(str, comp=false)
str = str.to_s
str = "#{$3}-#{$2}-#{$1}" if /(
\d{2})\.(\d{2})\.(\d{4})/ =~ str
parsedate_without_ru_format(str, comp)
end

alias_method_chain :parsedate, :ru_format
end
end

Подключаем этот код в config/environment.rb и вуаля: Rails понимает нужный нам формат даты.

3. Ошибка при неправильном формате даты.
Теперь формат понимаем, неправильное значение никуда не девается, осталось только понять, что формат даты неверный. В текущем состоянии при ошибке конвертации вместо даты имеем nil. Это может быть немного confusing для пользователя, если он думал, что он заполнил (необязательное) поле с датой и сохранил его, а потом выяснит, что в базе вместо значения получился nil.
При этом, не хотелось бы добавлять никаких явных валидаций (типа, validates_date_format :foo и т.п.). Итак: прикручиваем к ActiveRecord::Base валидацию по умолчанию, которая перебирает все столбцы модели и для всех столбцов типа :date проверяет, что если сконвертированное значение == nil, а значение *_before_type_cast не пустое (!foo_before_type_cast.empty?), то добавляет ошибку на это поле.
ActiveRecord::Base.class_eval do
class << self
def date_columns
columns.select { |column| column.type == :date }
end
end

def validate_dates_format(record)
record.class.date_columns.each do |column|
if record.send(column.name).nil? &&
record.send("#{column.name}_before_type_cast").empty?
record.errors.add(column.name, "has invalid date format")
end
end
end

validate :validate_dates_format
end

Данное решение избавляет еще и от проблем с невозможностью легко выставить дату для атрибута, который защищен от массового присвоения (посредством, например, attr_protected).

Надеюсь, описанный выше способ пригодится кому-нибудь (лично меня он полностью устраивает) или послужит источником знаний/вдохновения для написания "следующего самого клевого плагина для Rails".

PS Конечно, расширение стандартной библиотеки для поддержки своих форматов строк не самое изящное регение и черевато проблемами, если вдруг разработчики решат использовать какой-либо другой метод конвертации строк в даты. Но я считаю, что на данный момент этого решения вполне достаточно.

Read: Завершение саги о датах

Topic: Wonderful OpenID proxying Previous Topic   Next Topic Topic: Firebug ahora para IE, Opera, y Safari

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use