Rails中的相关模型验证 - 以及一些设计问题

时间:2011-01-03 21:54:39

标签: ruby-on-rails validation associations ruby-on-rails-3

我有一个有许多LoggedTimes的Task。我想在任何一天对任务设置8小时的记录时间限制。最好的方法是什么,以便我可以检查一个人的最新记录时间是否“超过限制”一天,可以这么说?

这是我开始的地方(Task.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个小时的先前记录时间,只需将其添加到其余部分,而不是抛出错误。由于没有抛出错误,我很难选择我的解决问题的方法。是否与处理params有关?

这让我想到了设计问题:理论上我可以修改视图,这样用户只能提交8小时减去他们当天记录的总时间;然而,这似乎是一个笨重的解决方案,并且违背了在模型中保持验证的原则。 (它肯定无法帮我解决这个模型验证问题)。

这里有什么建议吗?

TIA

3 个答案:

答案 0 :(得分:1)

我会创建一个单独的方法来获取给定日期的小时数。

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”而已。

答案 1 :(得分:1)

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 任务模型。

  • 当Task为nil时,绕过验证

修改

嗯,hours_today应该被称为minutes_today,但你明白了。

答案 2 :(得分:0)

我最后稍微修改了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?