親オブジェクトで検証を実行する前に、レール (3.2.8) を取得してネストされた属性を保存する方法を見つける必要があります。私は自分の問題に対する答えを長い間探してきましたが、同様の質問を見つけましたが、まだエレガントな解決策を見たことがありません.
状況は次のとおりです。
各 log_entry に複数のアクティビティがある activity_log があります。log_entry には「hours」というフィールドがあり、その日の合計作業時間を表します。各アクティビティには、そのアクティビティに費やされた時間を表す「時間」フィールドもあります。log_entry.activities.sum(:hours) が log_entry.hours を超えないようにする必要があります。
コードは次のとおりです。
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
問題は、params の新しいデータに対してチェックするのではなく、 activities.sum(:hours) を計算するときにデータベースに対してチェックすることです。したがって、log_entry の時間数を 4 に設定し、時間数を 5 に設定してアクティビティを作成すると、エラーなしで保存されます (db では activities.sum(:hours) == 0 と表示されるため)。しかし、同じレコードを編集してアクティビティの時間を 4 に設定すると、エラーが発生します (db には activities.sum(:hours) == 5 と表示されているため)。
ここで回避策を見つけました: http://railsforum.com/viewtopic.php?id=41562、しかし、この問題を解決するよりエレガントな方法があることを望んでいました。(実際には、この解決策は、説明したように機能しません。唯一の問題は、レコードが通過すべきではない検証に合格することであると想定しているためです。また、レコードが通過するはずの検証に失敗するという問題もあります。修正できると思います検証ステップをスキップしてから、コントローラーで (保存後に) sum_hours_not_more_than_total_hours のようなチェックを実行しますが、検証から得られる安心感が本当に気に入っています。)