Custom validation on nested attributes

跟風遠走 提交于 2021-02-19 04:03:08

问题


I need to find a way to get rails (3.2.8) to save nested attributes before performing validation on the parent object. I've searched a long time for an answer to my problem and, while I've found similar questions, I haven't yet seen an elegant solution.

Here's the situation:

I have an activity_log where each log_entry has multiple activities. The log_entry has a field called 'hours', which represents the total time worked that day. Each activity also has an 'hours' field, representing time spent on that activity. I need to make sure that log_entry.activities.sum(:hours) is not greater than log_entry.hours.

Here's the code:

class LogEntry < ActiveRecord::Base
  attr_accessible :date, :hours, :activities_attributes

  has_many :activities
  accepts_nested_attributes_for :activities

  validate :sum_hours_not_more_than_total_hours

  private
  def sum_hours_not_more_than_total_hours
    unless activities.sum(:hours) <= hours
      errors.add(:hours, "Hours cannot exceed total hours")
    end
  end
end

The problem is that it checks against the db when calculating activities.sum(:hours) instead of checking against the new data in params. So if I set a log_entry's hours to 4 and create an activity with hours set to 5, it will save with no errors (because the db says that activities.sum(:hours) == 0). But if I edit that same record and set the activity's hours to 4 it will give an error (because the db says activities.sum(:hours) == 5), when it should pass.

I found a workaround here: http://railsforum.com/viewtopic.php?id=41562, but I was hoping there was a more elegant way of solving this problem. (Actually, this solution doesn't work for me as described because it assumes that the only problem is that records are passing validation that shouldn't. I also have the problem that records fail validation when they should pass. I imagine I could fix it by skipping the validation step and then doing a check like sum_hours_not_more_than_total_hours in the controller (after save), but I really like the sense of security I get from validation.)


回答1:


instead of hitting the database with a sum-query, you could calculate the stuff based of the activities collection like this

self.activities.map(&:hours).sum


来源:https://stackoverflow.com/questions/17959632/custom-validation-on-nested-attributes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!