Поймать исключение, созданное в пользовательском методе доступа, до достижения проверки модели (и показать его пользователю с ошибками []) - PullRequest
5 голосов
/ 10 января 2012

Я просмотрел API и провел две ночи, уставившись на этот код, и, к сожалению, хотя я чувствую, что близок к решению, я не могу заставить его работать. У меня есть модель, представляющая смены, которые среди других атрибутов имеют время начала.

create_table "shifts", :force => true do |t|
  t.datetime "start"

Пользователь взаимодействует с этим как с простым временем, так как дата устанавливается в другом месте, поэтому я настроил виртуальные средства доступа для получения и установки.

class Shift < ActiveRecord::Base
  def start_time
    start.strftime("%H:%M")
  end

  def start_time=(time)
    date = start.midnight
    self.start = add_string_time_to_date(date, time)
  end

  def add_string_time_to_date(date, string_time)
    t = DateTime.strptime(string_time, "%H:%M")
    DateTime.new(date.year, date.month, date.mday, t.hour, t.min)
  end
end

Все это прекрасно работает при манипулировании через стандартный контроллер с @shift.update_attributes(params[:shift]), если ввести время в ожидаемом формате.

Я хотел бы проверить введенный формат времени, но он не так прост, как при использовании метода, описанного ниже, так как strptime() вызывает ArgumentError до того, как проверка будет достигнута.

validates :start_time, :format => { :with => /^([0-1][0-9]|[2][0-3]):([0-5][0-9])$|^/, 
  :message => "Invalid format." }

Я могу обойти это, поместив условный вызов в start_time(), например, в приведенном ниже примере, но на самом деле это не работает удовлетворительно по двум причинам.

def start_time=(time)
  if time =~ /^([0-1][0-9]|[2][0-3]):([0-5][0-9])$|^/
    date = start.midnight
    self.start = add_string_time_to_date(date, time)
  else 
    errors.add :start, "format invalid."
    nil
  end
end

Сначала ActiveRecord, похоже, не знает, что установщик не прошел. Я делаю это из факта, что update_attributes () в контроллере возвращает, как будто все было хорошо, даже если это не так. Во-вторых, обратная связь с пользователем не возвращается, поэтому вызов error.add, вероятно, находится вне контекста. Это также немного некрасиво.

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

Нужно ли вызывать конкретное исключение, чтобы уведомить ActiveRecord о сбоях, и если да, то где это лучше всего сделать? Лучше всего просто спасти и использовать вспышку?

1 Ответ

2 голосов
/ 17 октября 2012

Вам лучше разделить логику этих атрибутов.

  • Сначала определите attr_accessor для start_time (даже если он сохраняется только в памяти).
  • Затем инициализируйте значение соответствующим образом.
  • Окончательно установите атрибут запуска только при сохранении модели.

Это будет выглядеть так:

class Shift < ActiveRecord::Base
  attr_accessor :start_time

  after_initialize :default_values
  before_save :set_start

  def add_string_time_to_date(date, string_time)
    t = DateTime.strptime(string_time, "%H:%M")
    DateTime.new(date.year, date.month, date.mday, t.hour, t.min)
  end

  private

  def default_values
    self.start_time = start.strftime("%H:%M") if start_time.nil? && start.present?
  end

  def set_start
    if self.start_time.present?
       date = start.midnight
       self.start = add_string_time_to_date(date, time)
    end
  end

end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...