0

さて、私はRailsアプリにかなり簡単なものを実装しようとしていますが、Railsのコールバック、トランザクション、およびキャッシュは私をより良くしています。

これが私が達成したいことです:
2つのオブジェクトprojecttask。どちらにも属性がありますfinish_date。またproject :has_many => :tasks

私はproject、それ自体finish_dateが最新のものよりも早くなることは決してないことを伝えたいと思いfinish_dateますtaskstaskaが更新されるたびに、project親は必要に応じて自分自身をチェックして調整するfinish_date必要があります。

私はコールバックをいじっていafter_saveますが、トランザクションとメモリ内の同じオブジェクトの複数のバージョンのために、想像したほど単純ではありません。たぶん私はそれを間違っているだけです。

これをRailsに実装するにはどうすればよいですか?

4

4 に答える 4

1

Task次のモデルはどうですか。

class Task < ActiveRecord::Base
  belongs_to :project

  def after_save(task)
    self.project.finish_date = self.finish_date
  end
end

プロジェクトfinish_dateはタスクに設定されますfinish_date。コードは、現在保存されているタスクには常にfinished_date他のタスクと同じように後であると想定しています。それは間違った仮定です、ただ適切なifステートメントを追加してください:)

編集

コメントからの私の提案は、Task上記のように設定し、次のようにfinish_dateセッターを上書きすることです。Project

class Project < ActiveRecord::Base
  has_many :tasks

  def finished_date=(new_finish_date)
    self[:finish_date] = new_finish_date if self[:finish_date] < new_finish_date
  end
end

私は頭からコーディングしているので、この後にプロジェクトインスタンスを保存する必要があるかどうかわかりません。おそらくupdate_attributes、セッターで使用する方が良いかもしれません。

ここで他の解決策について

@Joeliosソリューションは、セッターをオーバーライドするだけでなく、私が行ったことを提案しました。それに関する問題は、Railsに含まれるメソッドが常にセッター(偶数update_attributescreate)を使用することです。それで、あなたはupdate_task_date自分でメソッドを呼び出さなければなりませんでしたが、それは忘れてしまうかもしれません。

@saveriosソリューションは、Observer/Observableパターンを使用することを提案しています。それで、私が見るように、そのすべてのオブジェクトProjectのオブザーバーになるでしょう。Task変更されると、Taskすべてのオブザーバー、つまりプロジェクトを呼び出し、プロジェクト自体がを更新しますfinish_date。デザインパターンを使用するだけで提案したものとほとんど同じではないため、より困難になります。

考えられるもう1つの解決策は、接続されているすべてのタスクを繰り返し処理して最新のを探すような新しい関数を定義するupdateことProjectですfinish_date。そのupdateメソッドは、タスクが更新されるたびに呼び出す必要があります。n個のタスクの1つを更新するたびに、n個のデータベースクエリがトリガーされ、すべてが遅くなるため、これは非常に悪い設計になります。

それが同じ問題に直面している誰かを助けることを願っています。

于 2012-10-08T20:29:23.770 に答える
1

uはafter_saveではなくtouchオプションを使用できます。

:touchオプションを:trueに設定すると、関連付けられたオブジェクトのupdated_atまたはupdated_onタイムスタンプは、このオブジェクトが保存または破棄されるたびに現在の時刻に設定されます。更新する特定のタイムスタンプ属性を指定することもできます。

class Task < ActiveRecord::Base
  belongs_to :project, :touch => :project_end_date
end
于 2012-10-10T06:57:11.350 に答える
0

あなたの問題が何であるかはわかりませんが、最初にコールバックなしで試してみてください。

update_task_dateというメソッドをタスクに追加します

def update_task_date(new_date)
  project.finish_date = new_date if self.project.finish_date < new_date
  project.save
  finish_date = new_date
  self.save

終わり

于 2012-10-08T20:23:18.640 に答える
0

オブザーバーはどうですか?モデルには他のモデルの知識がなく、その知識を別のクラスにカプセル化します。

http://api.rubyonrails.org/classes/ActiveRecord/Observer.html

于 2012-10-08T23:13:17.473 に答える