Связанные проверки моделей в Rails - и некоторые вопросы дизайна - PullRequest
0 голосов
/ 04 января 2011

У меня есть задание, у которого много LoggedTimes.Я хочу установить ограничение в 8 часов зарегистрированного времени для выполнения задачи в любой день.Каков наилучший способ сделать это, чтобы я мог проверить, если последний зарегистрированный период этого человека «, так сказать, превышает его общее количество» за день?

Вот где я начинаю (Задача.rb):

validate :max_logged_daily_time

def max_logged_daily_time
    if (params[:session_time] + (logged_times.where(:created_at => Date.today).to_a.sum(&:session_time)/60)) > 8
      errors.add_to_base("Can't have more than 8 hours logged a day") 
      logged_time.errors.add('session_time', 'Logged times exceeded today')
    end
  end

В настоящее время эта проверка не работает (добавление еще одного LoggedTime после того, как было зарегистрировано 8 часов предыдущего зарегистрированного времени, просто добавляет его к остальным, вместо того, чтобы выдавать ошибку. Поскольку ошибок нетброшенный, я изо всех сил пытаюсь разобраться в проблеме. Это как-то связано с обработкой параметров?

Что подводит меня к вопросу о дизайне: теоретически я мог бы пересмотреть представление так, чтобыПользователь может отправить только 8 часов минус общее количество времени, которое он зарегистрировал в тот день, однако это выглядит как неуклюжее решение и противоречит принципу сохранения проверок в модели (и это, конечно, не помогает мне решить эту проблему).проблема с проверкой модели).

Любой совет здесь?

TIA

Ответы [ 3 ]

1 голос
/ 04 января 2011
class Task < ActiveRecord::Base
  has_many :logged_times

  def hours_today
    LoggedTime.daily_hours_by_task(self).to_a.sum(&:session_time)
  end

end

class LoggedTime < ActiveRecord::Base
  belongs_to :task

  scope :daily_hours_by_task, lambda { |task| task.\
    logged_times.\
    where('logged_times.created_at >= ? AND logged_times.created_at < ?',
          Date.today, Date.today + 1) }

  validate :max_logged_daily_time

  private

  def max_logged_daily_time
    if task && ((task.hours_today + session_time) / 60.0) > 8
      errors.add('session_time', 'Logged times exceeded today')
    end
  end

end

Некоторые заметки:

  • created_at это DateTime, так что вы будете нужно проверить начало и конец дня

  • Проверка также предотвращает добавление одного LoggedTime, которое само по себе превышает максимум.

  • Деление на целое и усечение даст неправильный результат - добавьте .0 для преобразования в число с плавающей запятой.

  • Это только проверяет LoggedTime, не задача, так что вы можете добавьте validates_associated в Модель задачи.

  • Проверка обходится, когда задание равно nil

EDIT

Ну, hours_today действительно нужно назвать minutes_today, но вы поняли.

1 голос
/ 04 января 2011

Я бы создал отдельный метод для получения суммы часов за данный день.

def total_hrs_logged_for_date(date)
  #some code
end

Проверьте этот метод, чтобы убедиться, что он работает.

Возможно также сделать то же самое для вычисления текущего зарегистрированного времени.

затем используйте эти два в вашем пользовательском валидаторе

так что эта строка

if (params[:session_time] + (logged_times.where(:created_at => Date.today).to_a.sum(&:session_time)/60)) > 8

становится

if total_hrs_logged_for_date(Date.today) + current_time_being_logged > 8

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

Я также заметил, что у вас есть «params [: session_time]»

Я думаю, что это в Task.rb, который звучит как модель. Вероятно, вам нужно просто "session_time".

0 голосов
/ 04 января 2011

Я немного пересмотрел ответ Zetetic, потому что не мог заставить его работать как есть.

В конце концов это сработало:

class Task < ActiveRecord::Base
  has_many :logged_times
  validates_associated :logged_times

  def minutes_today
    logged_times.where('created_at >= ? AND created_at < ?', Date.today, Date.today + 1)
  end

end

и модель LoggedTime:

class LoggedTime < ActiveRecord::Base
  belongs_to :task

  validate :max_logged_daily_time

  private

  def max_logged_daily_time
    if task && ((task.minutes_today + session_time) / 60.0) > 8
      errors.add('session_time', 'Logged times exceeded today')
    end
  end

end

Я не уверен, почему метод видимости не работает, но это так. Любые намеки Zetetic?

...