3

親オブジェクトで検証を実行する前に、レール (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 のようなチェックを実行しますが、検証から得られる安心感が本当に気に入っています。)

4

1 に答える 1

2

合計クエリでデータベースをヒットする代わりに、このようなアクティビティ コレクションに基づいて計算できます。

self.activities.map(&:hours).sum
于 2013-08-10T19:28:25.877 に答える